Monday, September 22, 2008

I Notify Property Changes with Boo

It's now official. I've spend to much time of my life pondering about INotifyPropertyChanged. I've went from the naive
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}

to using helper methods like
FirePropertyChanged(MethodBase.GetCurrentMethod());

and even to more obscure helper methods this one (Relax, I've never used something like this in production):


MethodImpl(MethodImplOptions.NoInlining)]
protected void FirePropertyChanged()
{
var v = new StackFrame(1);
var name = v.GetMethod().Name.Substring(4);
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}



The best C# alternative I've come across to this point is the extension method found in the Umbrella project:


this.Notify(PropertyChanged, p => p.SomeProperty);

The implementation is rather neat, just take a look.


Better with Boo?

So, can we do better? I was recently introduced to Boo by a collegue, Tore Vestues. He showed how to auto-generate that boiler-plate code that goes into every property setter that needs to fire off PropertyChanged events. Simply mark the class with a [PropertyChanged] attribute and some fancy stuff happens compile time (you'll have to write that fancy stuff yourself, though). I like the approach alot, as it keeps your code cleaner. Combined with another property, [ExpandFields] that turns public fields into properties with backing fields, it gets even better. I wont go into details here and let Tore blog about it himself.


Based on the concepts he showed, I saw a nice opportunity to solve a little problem that has bothered me. It's been discussed over beer more than once, and no-one has ever managed to provide a truly good approach. Consider the following simple example:


class Presenter:

public Original as string

Dependant as string:
get:
return "Hello, ${Original}"

EventMoreDependant as string:
get:
return "${Dependant}, how are you?"



We have a field, Original, that has two properties that depend on its value. Wouldn't it be nice if changes to the field would fire off PropertyChanged events for all its dependants? The way I would handle changes to the Original field in C# is to change it into a property with a backing field. Then I'd add code to fire off the two PropertyChangedEvents.


For simple classes, I don't have a problem with that, but for more complex cases it becomes a chore to remember to fire PropertyChanged event from all the properties a certain property might depend on. And it's certainly not SoC.



So what's the point of this post anyway?

That's too much fluff before getting to the point, sorry about that. The point is, that by adding two attributes (ExpandFields, PropertyChanged) to the class, two things happen. First, all public field are converted into public properties with backing fields. Then, code is added to each property setter to fire off PropertyChanged events for all other properties that depend on it. Hard to explain, luckily Reflector does a better job at it:





And the unit test that confirms that it works:



[Test]
public void Original_WhenChanged_ShouldFirePropertyChangedForItselfAndDependants()
{
var presenter = new Presenter();

var set = new HashSet<string>();
presenter.PropertyChanged += (o, e) => set.Add(e.PropertyName);

presenter.Original = "Lars Andreas";

Assert.That(set.Contains("Original"));
Assert.That(set.Contains("Dependant"));
Assert.That(set.Contains("EventMoreDependant"));
}


If there's an interest, I'll clean up the code and put it out here. Boo is kinda cool :)

No comments: