Click here to Skip to main content
12,885,742 members (43,923 online)
Click here to Skip to main content
Add your own
alternative version


42 bookmarked
Posted 21 Dec 2007

Model-View-ViewModel in WPF

, 21 Dec 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
An article on creating WPF applications, following the Model-View-ViewModel pattern
Screenshot -


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.


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:






    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.


12/16/2007 - Initial article published.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

William E. Kempf
Web Developer
United States United States
Windows developer with 10+ years experience working in the banking industry.

You may also be interested in...

Comments and Discussions

GeneralA Word of Warning Pin
Mirko Klemm1-Sep-10 10:01
memberMirko Klemm1-Sep-10 10:01 
NewsAlternative approach with MEF Pin
jbe82244-Jul-09 0:53
memberjbe82244-Jul-09 0:53 
GeneralGood article Pin
CIDev2-Jun-09 7:54
memberCIDev2-Jun-09 7:54 
GeneralA little bit too complicated :/ Pin
john19977-Apr-09 3:17
memberjohn19977-Apr-09 3:17 
GeneralDataErrorInfo - ArgumentOutOfRangeException Pin
John Myczek15-Dec-08 9:00
memberJohn Myczek15-Dec-08 9:00 
I am using DataErrorInfo in one of my projects and it is working fine, but I noticed data errors (see below) in the Visual Studio output window. I was able to recreate the same error in your sample application:
1) Click Edit > Add Task
2) Enter a title and tab out of the field
3) Look at the Visual Studio output window:

System.Windows.Data Error: 16 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0).[0].ErrorContent; DataItem='TextBox' (Name='title'); target element is 'TextBox' (Name='title'); target property is 'ToolTip' (type 'Object') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at System.Collections.ObjectModel.ReadOnlyCollection`1.get_Item(Int32 index)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level)
at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'

This seems to happen anytime the field goes from an invalid state to a valid state. The validation still works, but I'd like to get rid of the exception in the output window.

Any ideas?
GeneralMy vote of 2 Pin
Jared Morton28-Nov-08 2:32
memberJared Morton28-Nov-08 2:32 
Generalmany interesting ideas Pin
Quang Tran Minh17-Jun-08 21:51
memberQuang Tran Minh17-Jun-08 21:51 
QuestionDataModel instance Pin
FantaMango776-Jan-08 20:33
memberFantaMango776-Jan-08 20:33 
GeneralRe: DataModel instance Pin
William E. Kempf8-Jan-08 10:49
memberWilliam E. Kempf8-Jan-08 10:49 
GeneralRe: DataModel instance Pin
FantaMango779-Jan-08 2:07
memberFantaMango779-Jan-08 2:07 
GeneralRe: DataModel instance Pin
William E. Kempf9-Jan-08 2:46
memberWilliam E. Kempf9-Jan-08 2:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170424.1 | Last Updated 22 Dec 2007
Article Copyright 2007 by William E. Kempf
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid