It would be good to have ability to raise \'PropertyChanged\' event without explicit specifying the name of changed property. I would like to do something like this:
The solutions already posted have a mix of two issues:
1) Some require you to create a base class and inherit from it. This is a huge problem that can throw a wrench in your classes inheritance chain and cause you to start re-designing your domain just to allow a development "extra" like this.
2) While the existing solutions allow you to designate which property to fire the changed event on via a lambda expression they still record and distribute a string representation of the property's name because they rely on the existing PropertyChangedEventArgs class. So any code that actually uses your PropertyChanged event still has to do a string comparison which again breaks any automatic refactoring you may need to do in the future not to mention your compile time support is out the window which is one of the main points of allowing lambda expressions instead of strings in the first place.
This is my generics version which follows the same event/delegate pattern started by MS which means no base classes and no extension methods are necessary.
public class PropertyChangedEventArgs : EventArgs
{
private readonly MemberInfo _property;
public PropertyChangedEventArgs(Expression> expression)
{
_property = GetPropertyMember(expression);
}
private MemberInfo GetPropertyMember(LambdaExpression p)
{
MemberExpression memberExpression;
if (p.Body is UnaryExpression)
{
UnaryExpression ue = (UnaryExpression)p.Body;
memberExpression = (MemberExpression)ue.Operand;
}
else
{
memberExpression = (MemberExpression)p.Body;
}
return (PropertyInfo)(memberExpression).Member;
}
public virtual bool HasChanged(Expression> expression)
{
if (GetPropertyMember(expression) == Property)
return true;
return false;
}
public virtual MemberInfo Property
{
get
{
return _property;
}
}
}
public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
public interface INotifyPropertyChanged
{
event PropertyChangedEventHandler PropertyChanged;
}
Now you can use it on a class like this:
public class PagedProduct : INotifyPropertyChanged
{
IPager _pager;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public PagedProduct() { }
public IPager Pager
{
get { return _pager; }
set
{
if (value != _pager)
{
_pager = value;
// let everyone know this property has changed.
PropertyChanged(this, new PropertyChangedEventArgs(a => a.Pager));
}
}
}
}
And finally you can listen to the events on that object and determine which property changed using a lambda expression as well!
void SomeMethod()
{
PagedProduct pagedProducts = new PagedProduct();
pagedProducts.PropertyChanged += pagedProducts_PropertyChanged;
}
void pagedProducts_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// lambda expression is used to determine if the property we are interested in has changed. no strings here
if (e.HasChanged(a => a.Pager))
{
// do something mind blowing like ordering pizza with a coupon
}
}