.NET & Funky Fresh

Syndication

News

  • <script type="text/javascript" src="http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;MarketPlace=US&amp;ID=V20070822/US/bluspiconinc-20/8001/8b68bf4b-6724-40e7-99a5-a6decf6d8648"> </script>
MVVM Study Part 4: Naked WPF

I’ve blogged previously about the MVVM pattern, but so far I have managed to escape without showing any code ;)  Before diving in deeper, I would like to stop and show what it takes to do a very simple implementation of this pattern on top of naked WPF (that’s plain WPF without any cool frameworks).

After all my praise of MVVM and how well matched it is with WPF/Silverlight, you might be surprised to hear me suggest that it’s not possible to implement without building a little infrastructure first.  It’s true.  But, we really only need to create one class:

public class DelegateCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func<bool> _canExecute;

    public DelegateCommand(Action execute)
        : this(execute, () => true)
    {
        _execute = execute;
    }

    public DelegateCommand(Action execute, Func<bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public void Execute(object parameter)
    {
        _execute();
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute();
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

The DelegateCommand is a common solution which allows us to adapt WPF controls, which accept an implementation of ICommand, to our ViewModel, which has simple properties and methods.  (If you want to make this work in Silverlight 3.0, you are going to have to build a little more infrastructure.)  Here’s an example of how you would use it as part of a fictitious employee creation screen:

public class CreateEmployeeViewModel : INotifyPropertyChanged
{
    private string _firstName;
    private string _lastName;

    public CreateEmployeeViewModel()
    {
        SaveCommand = new DelegateCommand(Save, () => CanSave);
    }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value; 
            NotifyOfPropertyChange("FirstName");
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value; 
            NotifyOfPropertyChange("LastName");
        }
    }

    public ICommand SaveCommand { get; private set;}

    public bool CanSave
    {
        get { return !string.IsNullOrEmpty(FirstName) && !string.IsNullOrEmpty(LastName); }
    }

    public void Save()
    {
        MessageBox.Show("Saved.");
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public void NotifyOfPropertyChange(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

The SaveCommand property allows us to use normal data binding in our view:

<Window x:Class="MVVMStudy.PartFour.CreateEmployeeView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="Height"
        Width="400">
    <Grid Margin="4">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        
        <Label>First Name:</Label>
        <TextBox Text="{Binding FirstName}" 
                 Grid.Column="1"/>
        
        <Label Grid.Row="1">Last Name:</Label>
        <TextBox Text="{Binding LastName}" 
                 Grid.Row="1"
                 Grid.Column="1"/>
        
        <Button Content="Save"
                Command="{Binding SaveCommand}"
                HorizontalAlignment="Right" 
                Margin="0 4 0 0"
                Grid.Row="2"
                Grid.ColumnSpan="2"/>
    </Grid>
</Window>

And in our code behind:

public partial class CreateEmployeeView : Window
{
    public CreateEmployeeView()
    {
        InitializeComponent();
        DataContext = new CreateEmployeeViewModel();
    }
}

Now you know a little more concretely what a WPF/SL dev means when they reference MVVM (Actually, all I have shown here is VVM.  Presumably you have a real employee model that you are saving in the save method or a web service you are calling.  That’s the missing M and isn’t really the focus of this series.)  But even then, this doesn’t get you very far.  If you are like me, you probably have a lot of questions still.  You might we wondering:

  1. What happens if I have a complex View Model with lots of properties and actions?
  2. How do I organize my View Models and Views?
  3. How do I pass contextual data to a View Model?
  4. Who creates View Models and associates them with the proper View?
  5. Do I really have to host instances of DelegateCommand on my View Model?
  6. How would I allow the user to work with multiple employees at the same time?
  7. How do I prevent unsaved changes from being accidentally lost?
  8. How do I handle dialogs?
  9. How do I manage contextual menus and toolbars?
  10. How long is this series going to go on?

We’ll take a look at answers to some of these questions in future posts.


Posted 11-13-2009 10:47 AM by Rob Eisenberg

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)