Tuesday, September 9, 2008

Enhanced INotifyPropertyChanged - Revisited

A while a go, I had a post regarding how to implement the INotifyPropertyChanged event in a more proper fashion. You didn't have to hard-code the property name, and could instead use a linq expression, which with a help of an extension method, the name of the property is easily extracted, and passed to raise the PropertyChanged event. Simple, right?

public static class EventExtension
{
public static void Notify<T, TValue>(this T instance, PropertyChangedEventHandler handler, Expression<Func<T, TValue>> selector)
where T : INotifyPropertyChanged
{
if (handler != null)
{
var memberExpression = selector.Body as MemberExpression;
if (memberExpression == null)
throw new InvalidOperationException("selector should be a MemberExpression.");

handler(instance, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
public abstract class NotificationAwareBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}

public class Customer : NotificationAwareBase
{
private string _Name;

public string Name
{
get { return _Name; }
set
{
_Name = value;
this.Notify(base.PropertyChanged, o => o.Name);
}
}
}

Should work like a charm, right? WRONG! you'll end up with a compile time error. It is like the extension method does not like my inherited PropertyChanged event. The drawback to the latter method was that you could not use it in inheritance context.

I need to implement INotifyPropertyChanged only once (Layer Supertype, anyone?). I had to come up with something to be able to work in inheritance context. Finally, here's it :

public abstract class NotificationAware : INotifyPropertyChanged
{
private event PropertyChangedEventHandler propertyChangedEvent;

public event PropertyChangedEventHandler PropertyChanged
{
add
{
propertyChangedEvent += value;
}
remove
{
propertyChangedEvent -= value;
}
}

protected void Notify<T>(T obj, Expression<Func<T, object>> selector)
{
if (propertyChangedEvent != null)
{
MemberExpression memberExpression = selector.Body as MemberExpression;
if (memberExpression == null)
{
UnaryExpression unary = selector.Body as UnaryExpression;
if (unary != null)
{
memberExpression = unary.Operand as MemberExpression;
}
}

if(memberExpression == null)
throw new ArgumentException("member should be of MemberExpression type", "selector");


propertyChangedEvent(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
public class Customer : NotificationAware
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
Notify(this, o => o.Name);
}
}
}

Happy coding!
Submit this story to DotNetKicks Shout it

2 comments:

Mohammad said...

Hi there Hadi.
Good work.
You have a very useful weblog.
I like your programming , special : http://www.codeproject.com/KB/selection/FarsiLibrary.aspx
Good and powerful.

Good luck

Anonymous said...

salam mr.eskandari
man dar hal neveshtane barname ei hastam va be komak va tajrobeye shoma niaz daram.dar soorate emkan baram mail bezanid ta betoonam ba shoma ertebat bargharar konam email e man samaneh.homayouni@gmail.com
kheili mamnoonam va montazere emailetoon.