共用方式為


DataModel-View-ViewModel pattern: 1

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

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.

ViewModel

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.

View

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.

Part 2: A DataModel base class

Comments

  • Anonymous
    July 24, 2006
    Trying to understand your distinction between VM and DM.  Is it right to say that a DataModel holds the data (or wraps the data) but the ViewModel holds view specific state like sort order, filtering etc...?
    In some cases you don't need a ViewModel because WPF provides it for you (DataTemplates etc..)

    If this is right then isn't your ViewModel the same as John Gossman's?  The only difference is that you have a DataModel and he has a plain Model.

  • Anonymous
    July 24, 2006
    A ViewModel is a bit more than that. It basically contains all of the behavior for a view and the view will have no codebehind. I hope it will become more clear as I build up an example. One of the key things is that it exposes things like commands and may aggregate several different DataModels.

  • Anonymous
    July 25, 2006
    Control Licensing in Cider (WPF designer for VS)James provides somegreat information on supporting...

  • Anonymous
    September 27, 2006
    If you're doing WPF development, you really need to check out Dan Crevier 's series on DataModel-View-ViewModel.

  • Anonymous
    October 11, 2006
    I thought I should add a post with the full list of posts in the D-V-VM pattern. They are: DataModel-View-ViewModel

  • Anonymous
    October 12, 2006
    By this: "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." Do you mean that the data model is also responsible for when to communicate out? If so, I'd say that you're violating the Single Responsibility Principle.

  • Anonymous
    October 12, 2006
    See part 6 for the activation model.