Tuesday, June 1, 2010

Implementing the Model View ViewModel pattern

Implementing the Model View ViewModel pattern: "

In this third part of my series of blog posts on the ViewModel pattern, I’m going to demonstrate how to implement a simple example of the ViewModel pattern. Not to worry, we’ll dive into more exiting examples later.

<Back to intro>

<Back to: The difference between MVVM and other Separated presentation patterns>

<Next: Adapting a simple vs complex model>

The ViewModel

So what is a ViewModel? And how does it differ from a View or the Model. Consider the following example. Suppose you would build Paint using WPF or Silverlight, using the MVVM pattern:

image

The View obviously determines what is displayed on the Screen. And the Model, well that will likely be the Image. But the application works with more data than ‘just’ the Document. This extra data is mostly the State of the UI. What brush is currently selected? What is the ‘zoom’ percentage? While it is possible to store this information in the View itself, this is usually a bad practice. For example, the zoom slider bar could be the place where you would store the zoom percentage. However, when more elements on the screen need to use the Zoom percentage, this value quickly becomes very hard to manage.

Model for the View

The ViewModel is a model for the view. Therefore, it hold’s all the state of the view as well as the logic that operates on the state. The ViewModel exposes this data and logic in such a way that the View can very easily access it. However, the ViewModel should not expose or interact directly with UI elements.

Another responsibility of the ViewModel is to adapt the Model to the View. Typically the Model is a domain model (we’ll dive into that more in a later blog post). If you have full control over the model, then typically you can build it so that the model itself is very easily databindable. However, if you don’t have control over the model, for example, you are getting it from an external system, then the ViewModel might need to adapt the model to the view. For example, by adding aggregations, combining information from different models or simply by implementing INotifyPropertyChanged to enable the ViewModel notifying the View that properties have changed.

The MVVM pattern

So the following picture shows the MVVM pattern as how you would typically implement it in WPF or Silverlight:

image

The View is typically implemented as a UserControl or DataTemplate (in WPF). It uses Databinding to read and update information on the ViewModel. For example, the ViewModel can expose a public property Name that can be bound to a textbox.

If the view needs to communicate to the ViewModel, there are several options:

Commands

To route the Click event from a button to a ViewModel, the easiest way is to implement a Command. The Command pattern describes an object that can invoke functionality at a later point in time. In this case, when the user clicks a button. We’ll dive into commands later in this post.

This defines the Commands in XAML:

   1: // Define the Commands



   2: public ICommand ShowCalorieKingInfoCommand { get; private set; }



   3: public ICommand ShowIngredientInfoCommand { get; private set; }



   4:  



   5: // Initialize the commands in the constructor with a delegate command.



   6: public MealDetailsViewModel(IDialogService dialogService)



   7: {



   8:     this.ShowCalorieKingInfoCommand = new DelegateCommand<object>(ShowMealCalorieKing);



   9:     this.ShowIngredientInfoCommand = new DelegateCommand<Ingredient>(ShowIngredientInfo, CanShowIngredientInfo);



  10: } 



  11:  



  12: // The methods called when the commands are invoked



  13: private void ShowMealCalorieKing(object notUsed) {..}



  14: private bool CanShowIngredientInfo(Ingredient selectedIngredient) {..}



  15: private void ShowIngredientInfo(Ingredient selectedIngredient) {..}




This snippet shows an example how to bind a command to a button in XAML




<Button Margin="10, 10, 10, 10" Content="Show information on CalorieKing.Com"
Commands:Click.Command="{Binding ShowCalorieKingInfoCommand}"/>





Pretty much only buttons allow you to use Commands out of the box. Now it’s possible (and not too hard) to create your own commands using attached behaviors).





2 way bindable properties




You can also use TwoWay databinding to notify the ViewModel that something has changed. For example, the following codesnippet shows how the DataGrid Control has a SelectedItem property. If you TwoWay databind this property to a property on the ViewModel.



Here’s the property in C#:





   1: public Ingredient SelectedIngredient



   2: {



   3:     get { return _selectedIngredient; }



   4:     set



   5:     {



   6:         if (_selectedIngredient == value)



   7:             return;



   8:  



   9:         _selectedIngredient = value;



  10:         OnPropertyChanged("SelectedIngredient");



  11:     }



  12: }




You can see that it also supports the INotifyPropertyChanged event. This means that the View will be notified if this value is changed in the ViewModel. And this is what the XAML would look like:




<data:DataGrid ItemsSource="{Binding Meal.Ingredients}"
SelectedItem="{Binding SelectedIngredient, Mode=TwoWay}" >





When I first started using the ViewModel pattern, I overlooked this capability. For example, I was looking for a way to attach functionality to the SelectedItemChanged event of the DataGrid. But two way databinding works a lot more directly. Just don’t forget to add the “Mode=TwoWay” tag ;)







Bind ViewModel methods to events from controls




The Caliburn framework allows you to bind public methods on the ViewModel directly to your controls in XAML. While this is a really cool technology, I also believe it makes your XAML more complex, because effectively, you are now programming (calling methods) in XAML. So I would personally try to either use commands, use two way databinding or implement an attached behavior (more on this subject later).




Code behind




It is always possible to use Code Behind to communicate between the View and the ViewModel. Whether this is a good idea is a topic of hot debate. I personally am of the opinion that there are better ways to solve this problem than to use code behind. In a later blog post, I’ll go into details why i think this is a bad idea and how you can avoid this. But there are people who think differently.






ICommand interface




A common way to expose functionality from your ViewModel that your Views can interact with is by exposing Command objects. A command object implements the ICommand interface.



The ICommand interface has two methods:




  • Execute, which will fire the logic encapsulated by the command


  • CanExecute, which determines if the command can actually execute.



The CanExecute is interesting. It’s a common scenario that you might wish to disable certain functionality, based on the state of your UI. This can easily be accomplished with a command. Because, when you bind a button to a command and CanExecute returns false, then the button will automatically become disabled.



Commands also have another advantage: They decouple the invocation from the actual logic. This allows for interesting scenario’s:




  • Binding multiple ui elements to a command


    Consider for example a SaveCommand. Often you don’t just have a Save Button, but also a Save menu item, and perhaps a save keyboard shortcut that will fire the same functionality. All these user gestures can be bound to the same command.


  • Chaining commands together

    You might also wish to bind several commands to a single UI element. For example, a certain type of ViewModel can expose a Save Command. However, you can have several instances of that ViewModel (with the corresponding view) open at any given time. A Save All button can be bound to all SaveCommands on all those ViewModels.



Silverlight doesn’t have Commanding support built in. Fortunately, it does support the ICommand interface, so there are several libraries available that provide Silverlight implementations of the ICommand interface. For example Prism (aka the Composite Application Guidance for WPF and Silverlight) and the MVVM Toolkit both provide a DelegateCommand implementation.



In my demo application, I’m also demonstrating the use of the DelegateCommand.




The INotifyPropertyChanged interface




One thing that you’ll find yourself implementing on your ViewModels the time is the INotifyPropertyChanged interface. This interface allows your ViewModel to notify the View of changes to properties.



This code snippet shows how to implement this pattern:





   1: // Public event (for the interface)



   2: public event PropertyChangedEventHandler PropertyChanged;



   3:  



   4: // Protected method for invoking the event from code



   5: protected virtual void OnPropertyChanged(string property)



   6: {



   7:     var handler = PropertyChanged;



   8:     if (handler != null)



   9:     {



  10:         handler(this, new PropertyChangedEventArgs(property));



  11:     }



  12: }



  13:  



  14: // Example property that triggers the property. 



  15: public Ingredient SelectedIngredient



  16:  {



  17:      get { return _selectedIngredient; }



  18:      set



  19:      {



  20:          // IMPORTANT: only trigger the event if someting actually changes!



  21:          if (_selectedIngredient == value)



  22:              return;



  23:  



  24:          _selectedIngredient = value;



  25:          OnPropertyChanged("SelectedIngredient");



  26:      }



  27:  }




One important thing: before invoking the event in the property, check if the value has actually changed. This helps preventing never ending loops when properties are chained together.



If you don’t like the repeating code you’ll get when implementing properties with INotifyPropertyChagned, you can also use ObservableObjects as properties, as I’m describing (among other things) in this blog post:



http://blogs.msdn.com/erwinvandervalk/archive/2009/04/29/how-to-build-an-outlook-style-application-with-prism-v2-part-2.aspx










What not to do in a ViewModel




There are a couple of things you shouldn’t do in your ViewModels:




  • Expose or interact with visual elements in your ViewModel


    Don’t try to expose Visual Elements, such as Buttons or other views from your ViewModel. This ties your UI to Visual Elements and makes it hard to test in isolation. Now you might run into the situation where your ViewModel needs to determine which view to display. In a later blogpost, i’ll describe how your ViewModel can be responsible for the logical ViewModel selection and use a DataTemplate to create the Visualization.




  • Try to control the View too directly from your ViewModel

    You should try to keep your ViewModel logical, rather than Visual. For example, if you want to color a control red in error situations, you could expose an “IsControlRed” property, or expose a brush in the red color. It’s usually better to expose the logical property, such as “HasError”. Then the UI designer can decide if the color of the control should be red or purple in an error situation.






Summary




This blog post describes the basics about implementing the MVVM pattern. In later blog posts, we’ll dive into more interesting scenario’s.

"

No comments:

Post a Comment