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);