Safe usage of INotifyPropertyChanged in MVVM scenarios


For my first post in this blog I’m going to describe how we can use the INotifyPropertyChanged without magic strings in MVVM scenarios by using lambda expressions. If you’re not familiar with this pattern you can read about it here:

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

When using MVVM we usually tend to create a base class that contains the INotifyPropertyChanged implementation as following:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    protected void RaisePropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

A simple ViewModel class could look like this:
public class SampleVM : ViewModelBase
{
    private string _sampleProperty;
    public string SampleProperty
    {
        get { return this._sampleProperty; }
        set
        {
            this._sampleProperty = value;
            base.RaisePropertyChanged("SampleProperty");

            this.IsEnabled = this._sampleProperty != null;
            base.RaisePropertyChanged("IsEnabled");
        }
    }

    public bool IsEnabled { get; private set; }
}

I’ve used this approach a lot and it works great but it has some problems.

The first problem is when you’ve got complex view models you often call RaisePropertyChanged outside your property declaration (for some reason I might want the IsEnabled property to be queried by my UI every time I update the SampleProperty). What happens if you want to refactor the IsEnabled property name to something else? Well sometimes you might forget to update one or two RaisePropertyChanged calls.

The second problem is that you can type a wrong string and your UI won’t complain, which makes it hard to track errors either at runtime or compile time.

The third problem is that you don’t have Visual Studio’s intellisense support to write the property name for you.

To solve all these problems you can simply change the ViewModelBase class to look like this:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    private void RaisePropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
    {
        if (propertyExpression.Body.NodeType == ExpressionType.MemberAccess)
        {
            var memberExpr = propertyExpression.Body as MemberExpression;
            string propertyName = memberExpr.Member.Name;
            this.RaisePropertyChanged(propertyName);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

The SampleVM class can be refactored as following:

public class SampleVM : ViewModelBase
{
    private string _sampleProperty;
    public string SampleProperty
    {
        get { return this._sampleProperty; }
        set
        {
            this._sampleProperty = value;
            base.RaisePropertyChanged(() => this.SampleProperty);

            this.IsEnabled = this._sampleProperty != null;
            base.RaisePropertyChanged(() => this.IsEnabled);
        }
    }

    public bool IsEnabled { get; set; }
}

Note that you don’t need to specify the generic parameter in the RaisePropertyChanged call because the compiler will do that for you thanks to generics type safety🙂

Also, if you want to reuse the code in other scenarios than MVVM you can always write a simple helper like:

public static class PropertyChangedHelper
{
    public static void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression, object sender, PropertyChangedEventHandler ev)
    {
        if (ev == null)
            return;

        if (propertyExpression.Body.NodeType == ExpressionType.MemberAccess)
        {
            var memberExpr = propertyExpression.Body as MemberExpression;
            string propertyName = memberExpr.Member.Name;
            PropertyChangedHelper.RaisePropertyChanged(propertyName, sender, ev);
        }
    }

    private static void RaisePropertyChanged(string property, object sender, PropertyChangedEventHandler ev)
    {
        ev(sender, new PropertyChangedEventArgs(property));
    }
}

And refactor the ViewModelBase to call it:

protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
    PropertyChangedHelper.RaisePropertyChanged<T>(propertyExpression, this, this.PropertyChanged);
}

I hope it helps everyone writing “safer” code!

11 thoughts on “Safe usage of INotifyPropertyChanged in MVVM scenarios

  1. I like this, though doing a test against sending a string vs this route, the expression way takes way longer.

    Looping through a million of these:
    SendPropertyChanged(propNameAsString) = 280ms
    SendPropertyChanged(Expression) = 4800ms

    • Thanks for your reply Ross.

      It should take longer if you loop a million times, but if you call it 10 to 100 times (assuming complex UI bindings) there is no difference at all😉

      Another way to do it is to declare static PropertyChangedEventArgs instances for each property that might change in your class and reuse them in the RaisePropertyChanged method.
      That would be the fastest way because you don’t need to instantiate the EventArgs objects nor get the property name through reflection and expression trees.

      Anyway.. I prefer to have cleaner code and the type safety offered by Expressions.

      • haha, I was just Googling around and forgot I posted that comment.

        I’ve been using your method more and more since I commented. I pretty much agree with you now. The type safety offered is way more useful than the insignificant speed difference in most cases.

        I actually made a little PathHelper class that does the resolving. It’s useful because you can also use it for creating paths for Bindings.

      • Hi Ross,

        It’s nice to know that!🙂
        I’m using it everywhere too. Actually I see no reason to keep using strings with this because its not as safe and defensive as using expressions.

        Perhaps you could tell us more about your PathHelper and what it really does?

        Thanks,

        MF.

  2. Hi, good idea.
    Another thing to watch out for is race conditions. You should take a copy the PropertyChanged event before checking it is null, otherwise some other thread may have preempted it and set it to null before you get to call it, resulting in an Null Reference exception.
    E.g.
    in RaisePropertyChanged …

    PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
    if (propertyChanged != null)
    propertyChanged(this, new PropertyChangedEventArgs(propertyName));

  3. Hello,

    Thanks for pointing that out Simon. Indeed, thats the best practice when firing events in multi-threaded scenarios.

    Although in this case, I believe that this solution doesn’t have that problem because I’m calling a method that will fire the event and I pass the PropertyChangedEventHandler delegate by value and not by reference, so the event that fires is already a copy.

    If, by any means, the event’s invocationList gets modified between this process the PropertyChangedEventHandler that gets fired will always be the one I passed to the PropertyChangedHelper.RaisePropertyChanged method.

    Because whenever a delegate’s invocationList changes, a new delegate is created with an updated invocationList, race conditions can happen when you fire events the traditional way..
    if(this.myEvent != null)
    this.myEvent();

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s