Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Model-View-ViewModel in WPF

0.00/5 (No votes)
21 Dec 2007 2  
An article on creating WPF applications, following the Model-View-ViewModel pattern
Screenshot -

Introduction

The Model-View-ViewModel pattern, a variant of Model-View-Controller, provides a nice way to develop graphical applications that are testable. Several features in Windows Presentation Foundation, such as data binding and the command architecture, go a long way towards making it possible to follow this pattern. Unfortunately, once you start to follow the pattern in a real application, you start to run into various things that make it very difficult to maintain the strict separation of Model, View and ViewModel. This article implements the basis of a full-featured application, illustrating various techniques that may be used to maintain the strict separation of concerns demanded by the M-V-VM pattern.

Background

I tried to implement this application while following the Behavior-driven Development methodology. I've captured the attempt by including a complete version history in the form of a Bazaar repository. Bazaar is a distributed version control system and, as such, the entire repository was included in the downloadable source archive. You can see every step of development, including all of the various mistakes I made while coding.

Despite the attempt to follow BDD, don't expect production-quality code here. First, I'm new to this methodology and you can be certain that I didn't follow it as well as one should. Second, although the project includes a fairly complete example application, it is only an example. I've focused on the necessary things to illustrate how to implement an application in WPF following M-V-VM, not on what would be necessary to make a production-worthy application. This is a starting place only.

Also, note that the unit-testing code uses a lot of custom code. This was a large enough portion of the effort that I split it out into a separate article: Visual Studio Unit Testing Extensions.

Using the Code

The "core" to a lot of the code in this project can be found in the ViewModel class. This class is both a MarkupExtension class, as well as a class providing a few attached properties. In order to associate your ViewModel with your View, you use the ViewModel class like this:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:CodeProject.Windows.Markup;assembly=CodeProjectCore"
    xmlns:vm="clr-namespace:TaskList.ViewModel;assembly=TaskList.ViewModel"
    c:ViewModel.Instance="{c:ViewModel {x:Type vm:MainWindowViewModel}}">

Assigning the ViewModel.Instance attached property does several things:

  • Assigns the property to an instance of an object. Note that this property is inherited by children.
  • Assigns the DataContext property to the same instance.
  • Assigns the ViewModel.Commands property to the empty string.

That last bullet point is worth explaining further. The ViewModel.Commands attached property is used to create command bindings on the View for command handlers in the ViewModel. This is actually one of the trickier things to accomplish in a simple and "clean" manner. I've blogged about this on my blog (check out the archives for several posts on this topic) and others, such as Brownie, have as well.

When ViewModel.Commands is attached to an element, it searches ViewModel.Instance for a property of type CommandBindingCollection with the CommandSinkAttribute and a matching KeyName. All CommandBinding instances in this collection are added to the element's Commands. This solution was inspired by the article Smart Routed Commands in WPF, although obviously the purpose and implementation are different here.

The ViewModel does not need to inherit from any base class or implement any interfaces. The ViewModel markup extension will try to instantiate an instance of the ViewModel first by looking for a constructor that takes a single parameter compatible with the element. You should avoid creating a tight coupling to the View here by using an interface that the element can implement. If the ViewModel doesn't have a constructor that fits the criteria here, it will instead be instantiated using the default constructor, if present. It's generally best to not create any coupling here at all, but there are some things you simply can't do in the ViewModel, such as navigate to another page. A View-specific interface allows you to put such code in the View while retaining as little coupling as possible.

A similar interface can be used for the Application. This gives the ViewModel access to application-wide settings and functionality, while not being closely tied to the actual Application. The sample application demonstrates using both the View interfaces, as well as an application interface, including how to use Mock Objects that implement these interfaces to facilitate testing.

The goal with the ViewModel is to put as much UI state as possible into it. The View then binds this state to the necessary elements. The classic example here is the selection state for a collection that will be presented in the View. The problem is that some states in the View are given in read-only properties that cannot be used in data-binding. The SelectedItems property on several controls is an example of this. In order to maintain such states in the ViewModel, a unique solution must be found to bind the state to the read-only properties on elements in the View. The Selection class provides an attached SelectedItems property to illustrate one way in which this can be accomplished. The attached property is responsible for watching the state both on the element as well as in the ViewModel, and keeping the two in sync.

Bonus: DataErrorInfo

This class isn't really related to M-V-VM, the main focus of this article. So, consider it a bonus. This is the starting point for a validation framework based on IDataErrorInfo. It uses various ValidatorAttribute classes to specify how properties are supposed to be validated. Only StringLengthValidatorAttribute is included in the code, but it should be straightforward to create other validators. The Task Model class illustrates the use and the EditTaskPage shows how to do validation with it in WPF.

History

12/16/2007 - Initial article published.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here