Refactoring Friendly INotifyPropertyChanged Properties
Reading time: 9 - 15 minutes
If you have been working on Windows Presentation Foundation or Silverlight 2.0/3.0 you may already be aware of a pretty interesting design pattern called MVVM (Model-View-ViewModel).
MVVM relies on the quite simple but important interface INotifyPropertyChanged in the System.ComponentModel namespace. Its role in MVVM is to allow you to notify when changes have occurred in your ViewModel so that your UI is able to respond to those changes.
// Summary:
// Notifies clients that a property value has changed.
public interface INotifyPropertyChanged
{
// Summary:
// Occurs when a property value changes.
event PropertyChangedEventHandler PropertyChanged;}
As you can see the interface is quite simple, it just ask us to implement the property changed event. The usual way to use it is the following:
private int myIntProperty;
public int MyIntProperty
{
get { return myIntProperty; }
set
{
if (myIntProperty != value)
{
myIntProperty = value;
OnPropertyChanged(“MyIntProperty”);
}
}
}
The “MyIntProperty” string is used to signal that the property that has changed is MyIntProperty so that our bindings gets notified of the value changed.
This approach has a slight problem, this string is not very refactoring friendly because it is binded to the property name, but it is not a “compiler verifiable entity”. In the case of the property it may look simple, just going ahead and change it. But, what happens when we are actually handling that property somewhere? Again we have to know that changing it will cause changes everywhere in our code base when that property change is handled.
If we do automatic refactoring, some tools may be able to know that they should change the property name too when refactoring and all strings. But that is a long shot if you have different classes with similar named properties, because the rename may change some strings that shouldn’t be renamed on the first place. Luckily there are workarounds to this problem.
What we would like to do is have something similar to this:
private int myIntProperty;
public int MyIntProperty
{
get { return myIntProperty; }
set
{
if (myIntProperty != value)
{
myIntProperty = value;
OnPropertyChanged(MyIntProperty);
}
}
}
The current version of the C# language do not support passing Properties as a delegate so we cannot create a runtime entity that may allow us to find out in the OnPropertyChanged event handler who is calling.
But we do have something that behaves in a similar fashion, we have Lambda Expressions and Expression Trees. So what if we can do the following?
private int myIntProperty;
public int MyIntProperty
{
get { return myIntProperty; }
set
{
if (myIntProperty != value)
{
myIntProperty = value;
OnPropertyChanged(() => MyIntProperty);
}
}
}
It turns out that this may work, as the compiler is creating an expression tree out of that delegate, so we may be able to extract the property name out of it.
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
After we solved that we are able to implement our PropertyChanged handler pretty easily like this:
/// <summary>
/// Raises this object’s PropertyChanged event.
/// </summary>
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName); if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected void OnPropertyChanged<X>(Expression<Func<X>> expression)
{
string propertyName = GetPropertyName(expression);
OnPropertyChanged(propertyName);
}
Now the only thing that we require is to implement a base class for our ViewModel and some helper class to encapsulate the GetPropertyName functionality and we are ready to have refactoring friendly INotifyPropertyChanged properties.
You can also download a complete implementation from here and 2 visual studio snippets, one for ViewModel classes that implement the INotifyPropertyChanged interface and another one for properties that notify they had been changed.
You can get it from: http://www.corvalius.com/blog/?attachment_id=26


Recent Comments