I have seen some demos of the Model-View-ViewModel (MVVM) pattern in the past. I was supposed to start another WPF project, but instead, given its importance in designing and coding WPF applications, I took time out to learn more about this pattern. Diving into the details does take some effort, but in this post I will simply outline the most rudimentary aspects of the pattern and go from there. This is by no means an exhaustive look at this pattern. I am just documenting my learning process and if anyone is interested, can follow along. What I will be doing in this post is to give a generalization of the pattern, without any of the WPF Commands and tests portions. Basically, it is to show how the subsections hook up to each other.
MVVM is a more WPF specific form of the Model-View-Presenter (MVP) pattern, by taking advantage of some of the features of the platform, such as data binding, data templates, resources, commands and routed events, to name a few. Of course you can dig out the details of these features from MSDN. In addition, there are some specific MSDN Magazine sections you can refer to:
The whole idea behind this pattern is the separation of concerns. That is, you can completely separate the presentation logic from the business logic of the application. This alone demonstrates the flexibility of the pattern in that you can have one group dedicated to the front end look/feel aspect of the app, whereas another team can tackle the more technical aspects of the project.
Let's take a brief look at each subsection of the MVVM pattern as shown in Fig. 1.
The Model is the section responsible for retrieving and exposing data to WPF in a way that it can understand. This data can come from a database, XML, RSS, or custom object. For example, given a XML file, you can create a custom object with public properties to model the elements of that file.
The task of this section is to abstract away some of the interaction logic from the View (UI) so that it remains purely just that - UI. In addition, since it stands between the View and the Model, the View never directly communicated with the Model. Instead, the View delegates the commands of the user to the ViewModel, which in turn performs the necessary logic to fulfill the user request. The ViewModel basically hold the presentation logic and state that is shared by the View(s). For example, imagine you have a custom class (our Model in this case) that exposes three public properties. However, the ViewModel only exposes two of those properties to all the Views of the application. Since the Views never have direct interaction with the Model, all it can do is interact with the two properties that the ViewModel exposes. I will go into more detail about it soon.
The ViewModel is also where you can implement the INotifyPropertyChanged and/or INotifyCollectionChanged since WPF does not provide automatic change notifications (the ObservableCollection class does support change notifications though). Since the ViewModel is data bound to its View, then any property that changes will be automatically propagated to the View. The ViewModel interacts with the View using the WPF Commands infrastructure. Also, each View will have its own corresponding ViewModel.
The View is the graphical front end of the application. It is basically a set of controls that is bound to a corresponding ViewModel object and should be entirely coded in XAML. No other code should be put in the accompanying code behind other than what was generated by Visual Studio. The View contains a reference to the ViewModel via its DataContext property. In order to render the ViewModel data to the user, the View uses Data Templates
I am using Visual Studio 2008 SP1 + .NET 3.5 SP1
Time for an example. If you download the MVVM files from CodePlex, it comes with a Visual Studio template to create a MVVM WPF project as in Fig. 2. The MVVM project will provide you with some additional boilerplate code, such as the DelegateCommand class and a test project (this is optional). In addition, the MVVM project has folders to separate the sections of the pattern as shown in Fig. 3.
For this example, you can use the CodePlex template or create a WPF project and add the Models, ViewModels and Views folders shown in Fig. 3. Since I have the template installed, I will just use that to generate the folders and for now, I will ignore the Commands and Tests parts of the solution.
I will start off with the Model by creating a super simple class called Person.cs and putting it in the Models folder. It will construct a Person object using firstName and lastName as arguments and expose two public properties. Note that this class is just an ordinary class and it has nothing to do with the MVVM pattern per say. You can rip this out and replace it if need be.
Since I am not pulling in any data from a file or database, I have added a method to this class to create some data points to test the example out with. This is shown in Listing 1.
This is basically all that is needed for the Model portion.
This is a very straightforward section as well. The MVVM Visual Studio template will create an initial view called MainView.xaml for you. This is where you will put the Views that is responsible for rendering your data. The pattern basically states that you should create UserControls to generate the necessary views. In simple cases you can probably just use the View that was automatically created.
For now, follow the pattern and in the Views folder, create a new UserControl called PersonView.xaml as shown in Listing 2. This control will be used to set the DataTemplate property of a ListBox control in the MainView.xaml file. The code in the PersonView UserControl is actually the code needed to create a template to represent the data. If you want you can delete this file and copy its contents to the data template section of the ListBox.ItemTemplate property in the MainView.xaml file as shown in Listing 3 and still get the same result.
This is where the majority of the fun stuff happens. Again, if you are using the template from CodePlex, there will be at least two ViewModel files generated for you - ViewModelBase.cs which is an abstract class that implements the INotifyPropertyChanged interface and the MainViewModel.cs which derives from ViewModelBase and is the View Model that is associated with the corresponding MainView.xaml View file.
In this example, I am creating a PersonViewModel.cs file in the ViewModels folder which will associate with the Person.cs Model. Basically, I am using this class (PersonViewModel.cs) to expose properties from my data class. Notice that in the Person class, I have two properties defined - FirstName and LastName. However, in the PersonViewModel class, even though I am creating Person objects, I am only exposing the FirstName property. This means that Views that are attached to the PersonViewModel will only see the FirstName property, which it exposes and not both properties as exposed by the original Model (Person.cs). This is to show that the View does not directly interact with the Model.
My PersonViewModel simply creates a Person object and exposes only a single property of the Person class. This is shown in Listing 4.
The MainViewModel class basically sets up a property that will be used to set the DataContext property of the View that binds to this ViewModel. What this means is that in this class, I will create a collection of PersonViewModel objects which in turn represents a Person (Model) object. This is an ObservableCollection which supports change notifications.
NOTE: The way I did this is not necessary here. I only used an ObservableCollection because I am trying to be as close to the MVVM pattern as possible. Since in this project I am not too concerend with changes in the collection, instead, I could have simply created a normal list of Person objects (List<Person>) and expose a property of the same type rather than exposing a property whose type is ObservableCollection<PersonViewModel> as shown in Listing 5.
The Persons property exposed by the MainViewModel class will be used to set the DataContext of the MainView which in turn has elements that data bind to whatever properties are exposed by each object of the collection.
The setting of the View's DataContex is done in the App.xaml file as shown in Listing 6.
A subset of the Class Diagram for the project is given in Fig. 4.
Now all you have to do is compile and run the application and you will get something like that in Fig. 5.