I just read an article by Micheal Sync about implementing property changed notifications with Expression Tree, I liked what I saw but didn't appreciate the inheritance requirement (as always). So I quickly whipped up three alternate way using extension methods, have a look:

using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace Orkpad.Samples
{
    public static class NotifyPropertyChangedExtensions
    {

        public static void NotifyPropertyChanged<TValue>(this Object target, 
            Expression<Func<TValue>> propertySelector, Action<string> notifier)
        {
            if (notifier != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    notifier(memberExpression.Member.Name);
                }
            }

        }

        public static void Notify<TValue>(this Action<string> notifier, 
            Expression<Func<TValue>> propertySelector)
        {

            if (notifier != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    notifier(memberExpression.Member.Name);
                }
            }

        }

        public static void Raise<TValue>(this PropertyChangedEventHandler handler, Expression<Func<TValue>> propertySelector)
        {

            if (handler != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    var _sender = ((ConstantExpression)memberExpression.Expression).Value;
                    handler(_sender, new PropertyChangedEventArgs(memberExpression.Member.Name));
                }
            }

        }

    }

    // I've tested this in Silverlight it works fine, should work in WPF too.
    public class NameValuePair : INotifyPropertyChanged
    {

        string _name;
        string _value;

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                this.NotifyPropertyChanged(()=> this.Name, RaisePropertyChanged);
                // I don't like to new up, but this is also usable
                //new Action<string>(RaisePropertyChanged).Notify(() => this.Value);
            }
        }

        public string Value
        {
            get
            {
                return _value;
            }
            set
            {
                _value = value;
                PropertyChanged.Raise(() => this.Value);
            }
        }


#region INotifyPropertyChanged Members

        void RaisePropertyChanged(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        public event PropertyChangedEventHandler PropertyChanged;

#endregion

    }
}

Of the three ways I've show, I like the last one using the PropertyChangedEventHandler best - it's quite compact and tidy. In fact, we can use similar extension-method "pattern" to call/raise handlers in various other scenarios. The other two ways are also useful if you don't have direct access to the event, like in cases of inheritance or where you have to go through a wrapper. Now, I can't speak to the performance of either solution - though, if someone can show figures on performance especially relative to the "normal way" that would be super!

// Recap

// Way 1
this.NotifyPropertyChanged(() => this.Name, RaisePropertyChanged);
// Way 2
new Action<string>(RaisePropertyChanged).Notify(() => this.Name);
// Way 3
PropertyChanged.Raise(() => this.Name);
 

Comments (7) -

Alexey Zakharov
Alexey Zakharov Russia
on 24-Mar-09 9:20 PM
Hi,

You've doing great work with your nRoute!! This post is also cool!!

Way 3 is really cool! My small remark: you don't need to write <this> - PropertyChanged.Raise(() => Name);

Thanks,
Alexey Zakharov.

Rishi
Rishi
on 25-Mar-09 4:18 AM
@Alexey, thanks for your kind words. And to <this> or not to <this> is a matter of personal taste, but ya, without that it becomes even neater.

Mike Brown
Mike Brown United States
on 11-Apr-09 8:49 PM
I like it. I had done something similar except my implementation involved reflecting on the sender to get the Event...didn't even think to make an extension off PropertyChangedEventHandler!

Great job as always.

Rishi
Rishi
on 17-Apr-09 12:50 AM
Thankz Mike, I'm going to include this next drop of nRoute but before that I'll put out some numbers on the performance. And maybe look to caching to see if performance can be helped.

Carlos Cubas
Carlos Cubas United States
on 30-May-09 9:36 PM
I seem to have hit a limitation on this approach.

It seems that we cannot call the Raise Extension Method, if the PropertyChangedEventHandler is defined in a base class.

Rishi
Rishi
on 03-Jun-09 8:43 PM
@Carlos, when using with a base class you can use either way 1 or way 2 (see above). The main requirement is that you have an inherited method (say called RaisePropertyChanged) that would raise the notificaiton when passed-in a property name. So something like this would do in your inherited class..

this.NotifyPropertyChanged(() => this.Name, RaisePropertyChanged);

Blackberry Screen Repair
Blackberry Screen Repair Canada
on 09-May-12 8:40 AM
I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

Pingbacks and trackbacks (5)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading