Reflecting Code

Thursday, April 1, 2010

Using custom attributes and binding to hook into another object's property change events.

I have a love / hate relationship with INotifyPropertyChanged (INPC). I love how it makes binding in Silverlight and WPF work so well. I hate how I have to dirty up my beautiful automatic properties. I spent many hours trying to make INPC work with automatic properties and I did succeed using PostSharp but I stopped using it for various reasons. I am not going to talk about that today but something else which is (in some respects) much cooler. [Check out this article for more info on PostSharp and INPC.]

I have been writing frameworks for years and last year I got started with the latest for Silverlight and RIA services. Our devs are doing MVVM and often they will include a RIA object in their ViewModels:

The problem with this approach is that although Customer implements IPropertyNotifyChanged there is no way to hook into it. Let's say that Customer has FirstName and LastName properties but we need a FullName property in our ViewModel to display in our view. This is a common scenario but very hard to accomplish. As you can see out CustomerViewModel has a FullName but if Customer.FirstName or Customer.LastName changes it will not be reflected on the UI.

[CallWhenPropertyChanged("Preferences.State")]public void StateChanged(object sender, PropertyChangedEventArgs e){Counties = CountyList.GetCountyNames(Preferences.State);}}The code below does just that. I created two attributes [NotifyPropertyChanged] and [CallWhenPropertyChanged]. The first is for properties and the second one is used on methods. CallWhenPropertyChangedis great when you have some common code (like calculations) that need to be executed each time a property changes.

Now that we have our attributes we need to create a Notification class with a dependency property to hold on to the property we for which we want to get notifications. This is the intercepting engine when given a property will set up a Binding and then call an action.

In our ViewModel we iterate through all of the properties and methods and look for the [NotifyPropertyChanged] and [CallWhenPropertyChanged] and create a Notification which will call our NotifyPropertyChanged or invoke a method.

This is the base to the ViewModel which allows you to use a lambda instead of just a string for the parameter for NotifyPropertyChanged which is checked at compile time. Misspelling a property name is an error which is really really hard to find. So I included this base but it is not required to use the Notifications I showed above.

So that's it. We use this in our current project since September and it works really well. I would like to thank Vaibhav Deshpande, one of our developers, who works with me on our framework. This is his idea to replace the PostSharp implementation we had earlier.