Note: If you’d rather just jump into the code the sample that goes with this post is here:
One of the features in WPF Starter Kit (http://wpfstarterkit.codeplex.com) that I am very proud of is the automatic change notification functionality. While implementing the INotifyPropertyChanged method in a base class makes our lives a little easier, it still means you lose the benefit of automatic properties that comes with C# 3.0. So instead of looking like this:
your view models typically end up looking something like this:
As you can probably tell, the OnPropertyChanged method in the BaseViewModel raises the PropertyChanged event on behalf of our view model. Now that might not look like a big difference when there’s just one property involved but maintaining a view model with several properties can quickly get out of hand. Add to that the fact that at some point, someone on your team will invariably end up changing the property name and forget to change the text in the call to OnPropertyChanged. What does this mean? This means change notification just stops working. Just like that. Pandemonium! 🙂
There are of course ways to mitigate this problem. Firstly, we could implement some sort of check in the OnPropertyChanged event to ensure that the string passed in does actually refer to a property on the current object. Here’s what our BaseViewModel looks like:
Notice the VerifyPropertyName method that gets called by OnPropertyChanged to verify the property’s name. This is a good solution, but there’s still a problem. Verifying the property name gives us runtime checking but it still doesn’t prevent code that causes this issue getting compiled and checked in. Finally, this still doesn’t solve the ugliness issue. Our view model still contains a LOT of code that does not have much to do with our business logic. Code that is just plumbing to support MVVM.
Enter interception! Interception is the technique we’re going to use to bring our view model code as close to the first code snippet (with automatic properties and no calls to OnPropertyChanged) as possible. With interception, our view model will look something like this:
A huge improvement, wouldn’t you say? So without further adieu let’s get started.
First, lets get set up:
1. Download the sample solution above and open it up. It has all the code we’re going to be talking about.
1. Start a new WPF Windows application
2. Add the BaseViewModel class shown above
3. You will already have a new Window called Window1. Add a class called Window1ViewModel:
4. Add a Loaded event handler to Window1 and add the following line of code to the handler:
What we’ve done here is set up a very simple example of Model View ViewModel (MVVM) where the ViewModel is supported by a simple base class. To add support for interception we will use the Unity Dependency Injection (DI) container (http://unity.codeplex.com/) released by the patterns and practices team. While Unity is by no means the only way to do DI in .NET, it is the one I am most familiar with. If you want to read up on the need and theory behind DI this is a good starting point: http://msdn.microsoft.com/en-us/magazine/cc163739.aspx. The next step is to go ahead and add references to all of the assemblies that ship with the Unity container.
Now we’ll write what in Unity parlance is called a “Call Handler”. A call handler basically handles a method (or in our case, property) call. What this means is that if you have a call handler set up on an object or type the call handler is executed before any methods (you get to choose which methods to target) of that object or type are called. What this lets you do is intercept the call and do something meaningful with what you have in the call handler. For example, a call handler might be used logging or to audit method entry points. A Unity call handler must inherit from the Microsoft.Practices.Unity.InterceptionExtension.ICallHandler interface. Here’s what ICallHandler looks like:
The Invoke method is where your call handler can do any work that it needs to. The Order property is the your call handler’s position (if there are other call handlers involved). We’re going to implement a call handler that:
- figures out whether or not the method being called is a property setter.
- figures out whether the value being set if different from the old value
- If 1 and 2 are true, find the PropertyChangedCallback event on the current or one of the base classes
- Check if the PropertyChangedCallback has any handlers assigned and if so, call those handlers
Here’s what the PropertyChangedCallHandler looks like:
Note how we use the getNext delegate to call the next interceptor (or the actual method) in line. This is VERY important because if we don’t do this the method being intercepted won’t actually get called. We definitely don’t want that happening now do we 🙂
The ShouldRaiseEvent method implements checks whether or not the method being called is a property setter and whether the value being set is different from the existing value. This is important because we only want to target properties for interception and we want to ensure we’re not raising the PropertyChanged callback without reason. The RaiseEvent method is where we actually raise the PropertyChanged event. Notice that it actually climbs up the inheritance hierarchy of the current type to find the PropertyChanged event. This saves us the task of implementing INotifyPropertyChanged in every single view model we write. Instead, we can just implement it is in the BaseViewModel (as we have) and rely on the call handler to find the event.
At this point you’re probably wondering how to link up the PropertyChangedCallHandler with our Window1ViewModel. We do this by passing on the responsibility of instantiating the view model to the unity container while telling it to set up the new object for interception with our custom call handler. To do this, we go change the code in Window1’s Loaded event handler from this:
What we’re doing here is:
- on line 2, we create a new Unity container
- starting on line 3, we tell the container to set up interception for the type Window1ViewModel. We also register the type with a name: Window1. We use a VirtualMethodInterceptor which basically means that all virtual methods (and properties) on objects of this class will be intercepted. We call this interception policy NotificationPolicy and get a reference to it.
- We add a matching rule for this policy that basically says we only want to look at properties and we only want to look at property setters. This makes some of the code in PropertyChangedCallHandler.ShouldRaiseEvent redundant but hey, better safe than sorry 🙂
- Finally, we add our PropertyChangedCallHandler to the policy
Basically what we’ve done is tell the unity container that we need it to intercept all objects of type Window1ViewModel and insert the call handler called PropertyChangedCallHandler in some of the method (property setters) calls. This can also be done using application configuration (app.config) and I encourage you to explore that option. The final step of the process is to clean up our view model. We don’t need the OnPropertyChanged call any longer. Here’s what the updated Window1ViewModel ought to look like:
Not bad huh! Note that we make the property virtual because we used the VirtualMethodInterceptor which is only capable of intercepting virtual properties and methods. Here’s the code for the sample:
The sample application is a simple application where the TestProperty is bound to a CheckBox as well as a TextBlock. When you check the CheckBox the TextBlock value gets updated to True and when you uncheck the CheckBox the TextBlock gets set to False (remember that in WPF, bindings are TwoWay by default). Here’s a couple of screenshots showing that:
Have fun. If you need to reach me, use the comment form below. This code (and lots of other useful stuff) is part of the WPF Starter Kit at http://wpfstarterkit.codeplex.com.