Bookmark and Share Share...    Subscribe to this feed Feed   About Christian Moser  


An elegant way to implement INotifyPropertyChanged

Introduction

A very common and popular way to synchronize data between the model and the view in WPF is using DataBinding. The value of the model is transferred to the view once, when the binding is initialized. But for every subsequent change, the model must notify the binding to transfer the value again. This is done by implementing the INotifyPropertyChanged interface on the model.

In the setter of every bound property there must be some code to raise the PropertyChanged event, passing the name of the modified property as a string. This has some disadvantages:

  • You cannot use Auto-properties
  • The property name is passed as a string. This brings ugly errors, when you forgot to change the string after a rename.
  • Every property needs extra code

The basic way to do it

 
private string _name;
 
public string Name
{
   get { return _name; }
   set 
   {
      _name = value;
      PropertyChanged("Name");
   }
}
 
private void PropertyChanged(string prop)
{
   if( PropertyChanged != null )
   {
      PropertyChanged(this, new PropertyChangedEventArgs(prop);
   }
}
 
 
 

A more elegant way to do it

The basic implementation requires two lines of code in the setter and the property name is passed as a string, which is not very robust. A more elegant solution is to use the power of expression trees to get the property name out of a lambda expression. The result looks like this:

 
private string _name;
public string Name
{
   get { return _name; }
   set { PropertyChanged.ChangeAndNotify(ref _name, value, () => Name); }
}
 
 
 
public static bool ChangeAndNotify<T>(this PropertyChangedEventHandler handler, 
     ref T field, T value, Expression<Func<T>> memberExpression)
{
    if (memberExpression == null)
    {
        throw new ArgumentNullException("memberExpression");
    }
    var body = memberExpression.Body as MemberExpression;
    if (body == null)
    {
        throw new ArgumentException("Lambda must return a property.");
    }
    if (EqualityComparer<T>.Default.Equals(field, value))
    {
        return false;
    }
 
    var vmExpression = body.Expression as ConstantExpression;
    if (vmExpression != null)
    {
        LambdaExpression lambda = Expression.Lambda(vmExpression);
        Delegate vmFunc = lambda.Compile();
        object sender = vmFunc.DynamicInvoke();
 
        if( handler != null)
        {
            handler(sender, new PropertyChangedEventArgs(body.Member.Name));
        }
    }
 
    field = value;
    return true;
}
 
 

The solution is ispired by the following articles:





Last modified: 2011-03-03 20:28:18
Copyright (c) by Christian Moser, 2011.

 Comments on this article

Show all comments
Adrian Cole
Commented on 4.March 2011
The property value needs to be set before the notification.
Jared Barneck
Commented on 8.March 2011
I am testing this out now.

Thanks,

Jared
Http://www.rhyous.com
Manu Reva
Commented on 26.April 2011
What about using Reflection, like &quot;MethodBase.GetCurrentMethod&quot;, for giving name of the property.
Do we expect performance issue ? or it is just too ugly :-)
Denis...
Commented on 12.July 2011
What about when you obfuscate the code?
Jim Yost
Commented on 21.July 2011
If I was debugging this code. I would appreciate the basic way

Name
E-Mail (optional)
Comment