.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]

Comments

DotNetShoutout wrote MVVM Study Part 4: Naked WPF - Rob Eisenberg - Devlicio.us
on 11-15-2009 2:19 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Jeff wrote re: MVVM Study Part 4: Naked WPF
on 11-16-2009 9:27 AM

THANK YOU! Finally i'm starting to understarnd MVVM :)

Wassim wrote re: MVVM Study Part 4: Naked WPF
on 11-20-2009 11:44 AM

Thank you Rob

Great article

Finally i'm starting to understarnd MVVM :)

Jeffrey wrote re: MVVM Study Part 4: Naked WPF
on 11-21-2009 8:19 AM

I understand that you now have de-coupled the view and the model and have a clean code-behind.

But what I fail to see in this example is why you wouldn't do this in your code behind. Sure you have seperated concerns now but I can't really see a good reason to do this in this example other then that you are now able to use different views on this viewmodel without having to re-write your viewmodel.

Is there more that I am missing? Can you give an (abstract) example where this seperation is a 'must' ?

Or should I just re-read the previous parts? :)

Rob Eisenberg wrote re: MVVM Study Part 4: Naked WPF
on 11-21-2009 9:57 AM

Jeffrey, for simple scenarios you can certainly do what you have suggested by setting the DataContext of the view to self. Personally, I don't prefer this because it complicates other things.  First, testing becomes a bit more difficult; not imipossible but more difficult. This is generally because of the threading nature of UI components. In order for tests to work right, you have to do a bit more setup and your tests are going to run slower. Second, it makes dependency management more complex.  If you are decoupling your components by using dependency injection, you now have to use parameterized constructors for your views.  This means you cannot directly instantiate views in Xaml any more and must rely on an IoC container to instantiate all your views.  But the most compelling reasons for me relate to two topics I have not yet discussed in this series (but certainly intend to).  These are the concepts of Screen Activation and Hierarchical VMs.  You can read a bit about Screen Activation at codebetter.com/.../what-s-hard-about-activating-screens.aspx   Again, I'm not going to say that this is impossible without a separate model, but it gets a lot harder.  Hierarchical models is something I use extensively, but almost no one has talked about.  You can get a basic sense of it from this article: www.codeproject.com/.../TreeViewWithViewModel.aspx  This technique woudn't work at all as part of the view.  So, what you are suggesting is a viable option, just know that you might create complexity in other areas, especially as your program grows.

.NET & Funky Fresh wrote MVVM Study Part 5: Convention over Configuration
on 12-14-2009 5:35 PM

In the last par t I showed a very basic view model. I needed something in order to give those new to

Orekaria wrote re: MVVM Study Part 4: Naked WPF
on 12-15-2009 3:29 AM

Nice code... I guess... because its not working.

I've tried it and... the save button is not activated when both fields are filled, but when you fill both fields AND change to other field.

Would you be so kind to fix the example for the real world, so as soon as you enter one word in the 2nd field the Save button become available?

Regards

Rob Eisenberg wrote re: MVVM Study Part 4: Naked WPF
on 12-15-2009 12:20 PM

@Orekaria

It works based on LostFocus of the controls.  Which is what triggers data binding by default in WPF and Silverlight. If you desire the button to be made available on TextChanged, you must change each of the UpdatePropertyTriggers on the bindings to PropertyChanged. Unfortuantely, this only works with WPF and not with Silverlight. I have been asking for MS to add the UpdatePropertyTrigger.PropertyChanged to Silverlight since the v1.1 Alpha and they still have not done so. I really hope they get it in the 4.0 release, because it is critical for real world apps as you have noted. The absences of such feature is often reported as a bug by application users (and developers). Thanks for addressing this issue.

iAwaaz-News-by-People wrote MVVM Study Part 4: Naked WPF - Rob Eisenberg - Devlicio.us
on 03-23-2010 9:42 PM

Thank you for submitting this cool story - Trackback from iAwaaz-News-by-People

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)