Filtering PropertyChanged events

Recently, while working on a CMS project, I had the need to update a part of the UI if certain values of my business object changed. Basically, the scenario was that if the name of a page changed, the navigational sitemap should also update to reflect the change.

The objects in our business library implement the INotifyPropertyChanged, so it's simple enough to subscribe to a PropertyChanged event. But I only wanted to determine if a select few of the properties changed so that I could trigger the display update. One way is to subscribe to the object's PropertyChanged event and simply write an if .. else or switch statement based on the property name being passed along.

Another was is to encapsulate the same functionality into a filter object; and that's just what I did by building the PropertyChangeFilter to pass those pesky PropertyChanged events through.

How to use the PropertyChangeFilter

/// instance of a MyObject business object that 
/// implements INotifyPropertyChanged
MyObject myObject = new MyObject();

/// create the PropertyChangeFilter to watch myObject
/// for changes in the Name and Title properties
PropertyChangeFilter filter = new PropertyChangeFilter(myObject, "Name", "Title");

// make the necessary changes to the object
myObject.Name = nameTextbox.Text;
myObject.Title = titleTextbox.Text;
/// .. snip other property assignments
myObject.Save();

if (filter.HasChanged)
{
    // handle changes to UI, clear a cached item, etc...
}

In the above example, we simply test to see if one of the properties we were listening for has changed. If either the 'Name' or 'Title' changed, the filter's HasChanged property would have been updated to suit.\

Passing events through the filter

The PropertyChangeFilter also implements the INotifyPropertyChanged interface, you can also subscribe to the PropertyChanged events of your object by using the PropertyChangeFilter as a proxy. So instead of getting all the PropertyChanged notifications, you get the ones your interested in.

In this example, which we follow on from our code above, we subscribe to the filters PropertyChanged event, which is raised only when the watched object's Name or Title change.\

filter.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
    Console.WriteLine("The '{0}' property has changed!", e.PropertyName);
};

It's worth noting that the sender argument is the object the event originated from and not our filter i.e. the sender is our instance of myObject.\

Getting a log of the changed properties

One last feature, if you could find a use for it, is to enable the TrackChanges property on the filter like so:

filter.TrackChanges = true;
myObject.Name = "Mouse";
myObject.Lives = 1;
myObject.Name = "Cat";
myObject.Lives = 9;
myObject.Title = "I R Weasel";
myObject.Name = "Amoeba";

string[] changes = filter.Changes.ToArray();
Console.WriteLine( "Log of properties changed: {0}", string.Join( ", ", changes ) );
// prints "Log of properties changed: Name, Name, Title, Name"

That's about all there is to it. It's simple, but yet another little C# Vitamin to help you along your way. You can download the full source code file for the class or the zip which includes a small demo console application.

comments powered by Disqus