John Gossman has blogged several times about the M-V-VM pattern for developing WPF applications. We’ve been using a similar pattern on the Max team, with slightly different terminology (DataModel instead of ViewModel). I thought I’d do a series of posts about some of our learnings here. With this pattern, you can make a well componentized application that cleanly separates the visual style from the behavior and makes the behavior code highly testable.
I know this post will probably bring in some comments about terminology. I’m just using the terminology we use on our team and it works well for us. Use whatever you like!
The elements of this pattern are as follows:
DataModel is responsible for exposing data in a way that is easily consumable by WPF. All of its public APIs must be called on the UI thread only. It must implement INotifyPropertyChanged and/or INotifyCollectionChanged as appropriate. When data is expensive to fetch, it abstracts away the expensive operations, never blocking the UI thread (that is evil!). It also keeps the data “live” and can be used to combine data from multiple sources. These sorts of classes are fairly straightforward to unit test.
A ViewModel is a model for a view in the application (duh!). It exposes data relevant to the view and exposes the behaviors for the views, usually with Commands. The model is fairly specific to a view in the application, but does not subclass from any WPF classes or make assumptions about the UI that will be bound to it. Since they are separate from the actual UI, these classes are also relatively straightforward to unit test.
A View is the actual UI behind a view in the application. The pattern we use is to set the DataContext of a view to its ViewModel. This makes it easy to get to the ViewModel through binding. It also matches the DataTemplate/Data pattern of WPF. Ideally, the view can be implemented purely as Xaml with no code behind. The attached property trick comes in very handy for this.
The lines between DataModels and ViewModels can be blurry. DataModels are often shown in the UI with some DataTemplate, which isn’t really so different than the way we use ViewModels. However, the distinction usually makes sense in practice. I also want to point out that there’s often composition at many layers. ViewModels may compose other ViewModels and DataModels. And, DataModels may be composed of other DataModels.
Next, I plan to work my way up to a sample that includes all of these layers. I also plan to include some examples of unit testing including some issues like dealing with Dispatchers.