What do you do when you want some functionality in your application that is too small to justify creating a full ViewModel, or that you want to reuse in different places and applications? You create a Sticky ViewModel. A Sticky ViewModel is a ViewModel that doesn’t replace the DataContext, but attaches itself to it and provides some functionality that closes a gap between what the model can do and what WPF needs.
While I want to introduce Sticky ViewModels in general in a later post, today I had the idea for a special case which is easy to implement and demonstrate: the Stateless Sticky ViewModel.
What is a Stateless Sticky ViewModel?
A Stateless Sticky ViewModel is a ViewModel that provides all its functionality in shared (static in C#) code, and stores all its state in attached properties. This pattern is suitable for cases where you have a simple dependency between a small group of values, all of which could be data bound.
For example, you might have a data model which exposes the name of a person as one property. In the UI, you’d like to edit first name and last name separately.
Implementing the Pattern
The first step in implementing the pattern would be to create a class that provides the code and attached properties. Since the class needs to define attached properties, it has to be based on DependencyObject. Then it would have to provide code in order to determine first name, last name and full name depending on what other information is already known.
Notice that all these functions are declared “Shared”. This means that we actually never have to create an instance of our ViewModel.
The next bit would be to declare the attached properties which contain the data and are bound to model and UI. Let’s take the FirstName property as an example:
The first three declarations are the standard declaration of an attached property: shared get and set methods, and the registration of the property with the property system. It contains a flag that causes the property to update any property to which it is bound by default, because this is what is probably supposed to happen if someone binds this property to their data model. But the most important point in this declaration is that it registers the OnFirstNameChanged method to be called every time the value of the property changes.
In the OnFirstNamedChanged method, we need to make the FullName property reflect the new value of the FirstName property. So, we need to call DetermineFullName and set the FullName property to the new value. In order to do that, we need the last name; since NameViewModel itself is stateless, we take this information from another attached property on the same object.
If we change the FullName property, of course its change handler will try to update the FirstName property. In order to avoid endless circular calls, we only set the FullName property if the value of the FirstName has really changed.
Tracking Dependencies Between the ViewModel’s Properties
But what is the meaning of the bit about the ChangeInitiator? Well, what would be the difference if we set “John A.” to the FirstName or to the FullName? In the first case, we’d expect the LastName to remain unchanged, in the second case we’d expect it to be set to “A.”. Since changing the FirstName changes the FullName and changing the FullName in turn changes the LastName, we need a way to determine that the LastName shouldn’t be changed in this special case.
In general, if we have multiple interdependent properties which all could be changed by the user, we need to make sure that the changes are propagated in the right direction. One way which helps in simple cases like this is storing a reference to the property which originated the change. Since we cannot store state in the ViewModel, we need another attached property:
This property is declared private, since it is intended for internal use, only. Using the ChangeInitiator property, we can make sure that property changes trigger other properties to change only if it is necessary.
Using the NameViewModel
We use the NameViewModel by binding the model’s Name property to the FullName attached property, and the user controls to the other properties.
Notice that since the ViewModel needs an object to which it can attach its properties, we name the Grid that hosts the other controls “SVMHost”, and refer to when binding to the Stateless Sticky ViewModel’s properties.
The approach introduced here has the advantage that it is very lightweight and has no dependencies whatsoever except those imposed by WPF itself. However, because the Stateless Sticky ViewModel is kind of scattered on the XAML elements that make up the view, it is prone to become confusing when the properties become many and their relationships become complicated. If you need a more structured approach, you could try a full Sticky Component or a Mini-ViewModel.
Shortly, I want to introduce Sticky Components and the WPFGlue Sticky Component Framework. However, before I do that, I want to get the Navigation Command off my desk, which I promised in one of the first posts…