Simplifying the implementation of INotifyPropertyChanged
Everyone that has written software using WPF or Silverlight recognize the amount of boilerplate code needed to define bindable properties. I dont know you, but to me it sucks to have simple properties with only a getter and a setter looking like this:
private int myProperty; public int MyProperty { get { return myProperty; } set { myProperty = value; this.Notify("MyProperty"); } }
Several other ideas have been implemented in frameworks like Caliburn and MVVM Light where we gain typesafe and refactoring friendly property notification using lambda expressions. A very clever trick I might say. However, IMHO the property definition syntax is still unnatural and unclear. In short a mess
.
private int myProperty; public int MyProperty { get { return myProperty; } set { myProperty = value; this.Notify(() => this.MyProperty); } }
A potential partial solution to this problem came with C# 4.0 with its ExpandoObject or dynamic objects in general. With them we can construct a very simple syntax at the expense of tying ourselves to a base class through inheritance (nothing we are not doing anyway with almost any INotifyPropertyChanged solutions).
public string MyProperty
{
get { return (string)this.Storage.MyProperty; }
set { this.Storage.MyProperty = value; }
}
That is achieved through the following base class definition:
public class SimpleNotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = (s, a) => { };
protected dynamic Storage { get; private set; }
protected SimpleNotifyPropertyChangedBase()
{
Storage = new ExpandoObject();
var asNotificable = (INotifyPropertyChanged)Storage;
asNotificable.PropertyChanged += (sender,arg) this.Notify(sender, arg);
}
protected void Notify(object sender, PropertyChangedEventArgs args)
{
PropertyChanged(sender, args);
}
}
This base class is actually a simple implementation that do not support almost any of the features that advanced frameworks like Caliburn.Micro or MVVM Light provides but it is simple enough to demonstrate how to implement it in there too.
On the practical side, the downside we found of using an ExpandoObject is that all properties must be defined prior to use them (in the constructor). Even though, that requirement could be easily lifted reimplementing our own ExpandoObject with a DynamicObject and returning default(T) if the property is not found; the exception is very useful as it allows to discover potential defects in our code.
Hope it is of use,
Happy Coding!!
@federicolois