If you have to implement and use IPropertyChanged in your code then you might feel annoyed by all the code that must be written to support the PropertyChanged event:
public class Product : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _productId;
public int ProductId
{
get { return _productId; }
set
{
_productId = value;
RaisePropertyChanged("ProductId");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Not only is this code trivial and repetitive but since the property name is passed as a string then it can easily lead to typos. Luckily there is a better way to do this:
public class Product : PropertyChangedBase<Product>
{
public int ProductId
{
get { return GetPropertyValue(x => x.ProductId); }
set { SetPropertyValue(x => x.ProductId, value); }
}
public string Name
{
get { return GetPropertyValue(x => x.Name); }
set { SetPropertyValue(x => x.Name, value); }
}
}
PropertyChangedBase:
public class PropertyChangedBase<T> : INotifyPropertyChanged
{
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected TProp GetPropertyValue<TProp>(Expression<Func<T, TProp>> property)
{
var name = GetPropertyName(property);
return (TProp) _properties[name];
}
protected void SetPropertyValue<TProp>(Expression<Func<T, TProp>> property, object value)
{
var name = GetPropertyName(property);
_properties[name] = value;
RaisePropertyChanged(name);
}
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private string GetPropertyName<TProp>(Expression<Func<T, TProp>> property)
{
return (property.Body as MemberExpression).Member.Name;
}
}