Introduction

As demonstrated in the article Simplifying the WPF TreeView by Using the ViewModel Pattern by Josh Smith, inserting a Presentation Model layer between your domain-model collection contents and template-generated WPF classes can make using WPF easier. Josh showed how to avoid writing procedural code against template-generated items such as instances of TreeViewItem. Attempting to do so causes headaches, making WPF seem more like a burden than a boon. WPF works fine when you're setting properties of template-generated items in XAML, but that ease of use is lost if you try directly doing so in the code-behind file. So save yourself the agony by taking an indirect approach.

In order to access and modify properties of template-generated items from the code-behind file, you first need to bind them to whatever is in the control's ItemsSource collection. Many of the properties you want to bind to (e.g., IsSelected and IsExpanded) will not be present on your domain objects, nor do you want to add them there since they are GUI-related rather than domain-related. The solution, as Josh presented in his article, is to create an additional Presentation Model layer consisting of objects that sit between your domain-model collection contents and the template-generated instances of WPF classes.

During the course of your adventures in WPF, it's likely you'll find other properties that are appropriate to the Presentation Model layer. These are properties that are clearly more GUI-related than domain-related, but would be quite convenient to have available as data-binding sources (without otherwise relying on value-converters). This article and the accompanying code library expand on this idea. The library makes it easy to create a new Presentation Model, of the sort just described, with minimal code. The ItemPresentationModel class provides a presentation-tailored representation of a domain-model type. And the HierarchicalPresentationModel class helps you by propagating modifications from a domain layer collection or tree structure, into a hierarchical Presentation Model.

Terminology

Two very similar design patterns have been described, each of which uses slightly different terminology. The original Presentation Model pattern by Martin Fowler uses the word "Presentation" to refer to the UI, whereas the latter WPF-specific Model-View-ViewModel by John Gossman uses "View". I prefer the original, and will use it throughout this article.

As for domain-specific Presentation Model classes, there is no universally accepted naming convention. The example in Fowler's work uses the combination of "Pmod" + domain class name, as in "PmodAlbum". Josh Smith's article started out using domain class name + "Presenter", but a reader pointed out that "it is somewhat of a misnomer". He therefore switched over to domain class name + "ViewModel", which follows John Gossman's terminology. For a while, I suffixed "View" onto Presentation Model classes, but this word's prominent use to refer to the UI layer has since led me to suffixing "PM" instead.

Presentation Model in WPF

This article isn't about the Presentation Model pattern per se. Fowler writes that "Presentation Model is not a GUI friendly facade to a specific domain object". However, the form of Presentation Model I use provides a data-binding friendly facade for each domain object to its corresponding template-generated item (e.g., TreeViewItem). This variation of the pattern is what I call "Item Presentation Model", and has a corresponding base class by the same name in the library attached to this article.

This ItemPresentationModel class wraps a domain object (the "Item") with a Presentation Model. The domain object is publicly accessible via the class's "DomainItem" property. This means you don't have to bother writing repetitive bridging properties of the form:

publicstring RegionName {
get { return _region.RegionName; }
}

where no value is being added, since you have direct access to the wrapped domain item.

Flow of Changes

Displaying current data on all screens is generally required of an application. Neglecting this, as I've seen in other WPF-related articles on the web, can lead to problems as the codebase grows. For example, if Domain Model object dm1 has two corresponding Presentation Model objects pm1 and pm2, and if pm1 modifies dm1, then pm2 will contain stale data. The same problem can occur, for both pm1 and pm2, if some logic within the Domain Model modifies dm1. The solution is to make the Domain Model observable, so changes automatically flow to the Presentation Model.

Demo 1

This example demonstrates how easy it is to create a subclass of ItemPresentationModel. The code for the Demo1ItemPM Presentation Model class is as follows:

UnsavedName is exactly the sort of property you would add to the Presentation Model, since it's not something that belongs in the domain-model, yet its use with data-binding makes things easier. Here's the text box for editing an item's name:

If the saveButton is clicked, then the domain object's name is updated (after which you would persist the change to the database). If the cancelButton is clicked, then the UnsavedName value is reset.

Run the demo, and look at the source code of Demo1.xaml and Demo1.xaml.cs, for further details.

Demo 2

Now we move on to representing hierarchical domain-model structures, with a Presentation Model that interfaces with template-generated TreeViewItems. For this example, we have a SampleTreeNode domain class and its corresponding SampleTreeNodePM Presentation Model. The superclass of SampleTreeNodePM is my library's HierarchicalPresentationModel base class. It wraps individual items of the domain tree-structure, and has a recursive SubItems property that is used in the HierarchicalDataTemplate:

When you instantiate a root object of this wrapper type (see code snippet below), it populates its tree with items from the domain tree-structure, first wrapping each one. You then bind this root object's SubItems property to TreeView.ItemSource (the following line in the snippet). But if the domain-model thereafter changes, how can the Presentation Model be updated to reflect those changes? For example, if the user removes a SampleTreeNode object's sub-item, how can that change be propagated to its corresponding SampleTreeNodePM? Luckily, my HierarchicalPresentationModel class takes care of that synchronization for you. After being created, each HierarchicalPresentationModel object listens to its corresponding domain collection's change events, adding/removing sub-items to/from itself as to stay in sync.

So a HierarchicalPresentationModel object acts as a sort of custom collection-view (analogous to WPF's CollectionView) over an original domain-model sub-items collection. The binding from a domain collection to its corresponding collection-view is one-way; that is, changes to the domain collection affect the collection-view but the reverse is not true. The binding from a collection-view to the ItemsSource property of its corresponding TreeView (if it's a root) or TreeViewItem (for all other nodes) is also one-way. In order to programmatically add/remove items, the client code modifies the domain collections; those changes are then propagated in the desired manner all the way to the TreeView or TreeViewItem.

An override of the CreateInstance() method that returns an instance created via the latter constructor.

An override of the DesiredPosition() method which, in this case, uses the simplest of implementations, i.e. add the new item to the sub-items collection. The third argument to the return value's constructor is false, indicating the resulting collection is not sorted.

As for the base constructor call in #2, you may be wondering what are the three boolean values being passed through:

Specifies whether the Presentation Model subitems' indices are the same as in their corresponding source collection. We are mirroring the domain hierarchy exactly, so in this case the value is true.

Specifies whether subitems also get deleted once their parent is deleted, which is also true in this case.

Information useful for debugging DesiredPosition() implementations is written to the console when this value is true.

HierarchicalPresentationModel derives from ItemPresentationModel, so deriving from it gives you the same properties mentioned for Demo 1, as well as Josh's IsExpanded property which gets data-bound like this:

Use SampleTreeNodePM as a template in your own projects. And check out the rest of the Demo2 code-behind file to see how to add, move, and remove nodes from the tree structure.

Demo 3

The HierarchicalPresentationModel class has another use, which is to provide a hierarchical representation of a flat collection. That is, given the input of a flat collection from the domain model, this class can help you produce a hierarchical Presentation Model ready to be data-bound to a TreeView. There are a couple of different ways to do this in WPF, but this is the only way I know to take a flat collection and display some items as children of others.

The original purpose of the HierarchicalPresentationModel code was, in fact, to display a flat collection as a hierarchy. This was my first use of the Presentation Model pattern, before I even knew what the Presentation Model pattern was! Adding the data-bound IsSelected and IsExpanded properties was an advantage I realized only later, after coming across Josh Smith's Simplifying the WPF TreeView... article.

The demo here uses the same domain data as Demo 1. It may be interesting to compare Demo 1 and 3 since they display the same data, only using a different Presentation Model.

This subclass consists of the same four parts as the one in Demo 2. You will notice a difference in the private constructor, however. In this case, a null value is passed in for the base constructor's subItemsSource parameter. This indicates that no sub-items will be recursively created by the base constructor, which is what we want in this case since the DesiredPosition() method will decide the subtree's arrangement. Following that, you'll notice the first two boolean values are also different from the previous demo: subitem indices do not correspond in this case, and deletes do not cascade.

The body of the DesiredPosition() method is omitted because it's a bit long. If you have a similar scenario, though, then you should take a look at it. Apart from the specific types mentioned (Represented and Representative), the logic may be applicable to your situation. After that comes the RepresentedBy bridging property, which I added since it made data-binding to the representedByComboBox so much easier:

The problem was that two different subclasses are involved — one that has a RepresentedBy property, and another that doesn't. This bridging property prevents a binding error by just returning a null value when the RepresentedBy property isn't present.

Share

About the Author

Adrian loves facilitating suave user experiences via the latest and greatest GUI technologies such as Windows 8 Metro-style apps as well as WPF. More generally, he finds joy in architecting software that is easy to comprehend and maintain. He does so by applying design patterns at the top-level, and by incessantly refactoring code at lower levels. He's always interested in hearing about opportunities for full or part-time development work. He resides in Pennsylvania but can potentially travel anywhere in the country. (Writing about himself in the third-person is Adrian's new hobby.)

Nice article, but one concern I have is how you would handle property change notifications for the GUI? Typically all of the properties of a ViewModel need to generate INotifyPropertyChanged notifications so the GUI knows that a property value has changed. Since you wrap the original item inside your ItemPresentationModel and access the properties directly from DomainItem, how do you trigger change notifications? Or are you expecting the Models themselves to generate property changed notifications?

are you expecting the Models themselves to generate property changed notifications?

Yes, that is the general expectation. However, I've gotten by so far without my models implementing INotifyPropertyChanged, as you can see from the demos. Instead I've been relying on the WPF data-binding engine subscribing to the property-changed event through the PropertyDescriptor.AddValueChanged() method. Check out this thread, in particular the answer posted by Marco Zhou, to see what I mean.

This approach does effect how I update the model, though. While writing the updateButton_Click() method for Demos 2 & 3, I first tried setting sampleTreeView.SelectedItem.DomainItem.Name with the new value directly, but that didn't have desired effect on the UI since the source doesn't implement INotifyPropertyChanged. So instead I use BindingExpression.UpdateSource(),

Thanks for the comments, guys. Actually I already added some code snippets and further explanation to Demo 3; I just haven't sent them into Code Project yet (what address do I use btw?). Next I'm going to read through the rest of the article, looking for other spots where code snippets would be appropriate. If you have anything specific in mind, please let me know.

Please let me know if there's anything in the article you feel I could improve upon.

Nice article, in general. Thanks for posting it.

I voted the article a 4. If the article had more code snippets, especially in the Demo 3 section, I would have given it a 5. If you're looking to improve the article a bit, I suggest you show a bit more of how your code works. If you make some enhancements, please let me know, and I will bump up the vote to a 5.