Latest Tweet:
  • Loading...

Yesterday I published a post showing how we can use AOP and Castle Dynamic Proxy to get automatic change notification for ViewModels by intercepting property setters. One of the comments I got was from Krzysztof Koźmic who suggested that I should use ProxyGenerationHook to narrow down the scope of the proxy.

By implementing the IProxyGenerationHook we get to choose which methods to intercept. In my original implementation this logic was handled by the interceptor itself. The interceptor would check that the method being intercepted was indeed a property setter, that it was not of type ICommand, and that it was not marked for exclusion. By implementing a ProxyGenerationHook I could move all this code into a separate class, making my interceptor much cleaner. The ShouldInterceptMethod implementation of the ProxyGenerationHook now looks like this:

ProxyGenerationHookCode

I also got a good question from Anders Knutsen asking how to handle change notification for properties depending on another property. A typical scenario for a ViewModel might be to have a ZipCode-property with both setter and getter, and City and State properties with only getters. When you set the ZipCode you raise change notification for ZipCode, City and State. In the City- and State-getter you look up the values based on the ZipCode. This means that you must be able to raise multiple change notifications in a single setter.

I solved this by adding a new NotifyChangesFor-attribute that you can decorate properties with to trigger change notification for additional dependent properties.

NotifyChangeForAttributeCode

I have also updated the tests to document this behavior.

NotifiyChangesForTestCode

The sample code has been updated with the new ProxyGenerationHook and the new NotifyChangesFor-attribute.

Thursday, December 24, 2009 9:40:27 AM (W. Europe Standard Time, UTC+01:00)
Really enjoyed these blog posts, Jonas. Nice.
I'm not so sure about the NotifyChangeForAttribute though. IMHO you either want a different design that encapsulates the concept that a postal code identifies both a city and a state like:

class Postalcode {
string code
string city
string state
}

If you do this, you're vanilla flavored solution is good. The other way is to raise a NotifyPropertyChangedEvent from within the setter for postal code. After all its the "business" logic inside this setter that changes the other properties, not passing the data to in.
Monday, December 28, 2009 11:22:25 AM (W. Europe Standard Time, UTC+01:00)
One problem with this way of solving the issue of dependent properties is that it is somewhat a step back in terms of having to hard-code the property names as strings, which makes the code harder to change (although the City and State-properties are pretty unlikely to change). It does however cut back on the amount of code you have to write and makes the code easier to read.
Tuesday, December 29, 2009 5:49:17 PM (W. Europe Standard Time, UTC+01:00)
NotifyChangesForAttribute is a nice idea. On the other hand you introduce back the magic-strings into the code. This makes the whole process pointless since we want strong-typed property names in the code.
Nikos Baxevanis
Wednesday, December 30, 2009 3:41:39 AM (W. Europe Standard Time, UTC+01:00)
I used Postsharp before for the same purpose and although we used strings we were checking for them at compile time. I'm not sure if it would be a good idea to check that the property exist at runtime when we build the interceptor for TViewModel.


About derived properties, I did it the other way around. Instead of saying that ZipCode should notify for City and State, I would say that City depends on Zip.

[DependsOn("Zip")]
public string City{get;}

I use this mainly for derived properties. Let's give another example that shows the actual implementation. A derived "Total" property for a Line Item that depends on Quantity and Price.

//[NotifyChangeFor("Total"] <-- This seems wrong to me. Since qty shouldn't know that other props depend on it
public int Quantity{get;set;}
//[NotifyChangeFor("Total"] <-- This seems wrong to me. Same as above
public float Price{get;set;}
[DependsOn("Quantity","Price"]
public float Total {get { return Quantity*Price;}

As I mentioned on your other post about "purity", I think that the Depends or NotifyFor attribyte adds knowledge to our VM about this concern that we tried to push to our interceptor. Anyway I can't think of a cleaner approach that and this seems to work quite well.
Wednesday, December 30, 2009 4:58:36 PM (W. Europe Standard Time, UTC+01:00)
Anders N: Create a "dumb" class with only property names to "glue" the concepts together, but still have the three properties exposed on the VM? Or expose the Postalcode object directly? If so - you would still have to solve the change notification issue.

Anders K: You are right - this solution do bring back magic strings, which is bad. I do think that for a "real" app I would probably just write the code in the ZipCode setter like Anders N suggests - to make the relationship clear and avoid strings. To avoid strings I would use LINQ Expression based syntax like:

this.RaisePropertyChanged(() => this.City);

This way you could have automatic implementation for "dumb" data properties, and strongly typed notification for "complex" properties like ZipCode. I do gives you two ways of doing INPC - but I do think that wouldn't be all that bad.

I'll try a few approaches for my next blog post on integrating this to the IoC. One of the things I will probably do is remove the IAutomaticChangeNotification, and instead use the plain interface, and use a convention based on name or registration technique that tells the container to do automatic change notification.

Miguel - let me know if you can come up with a good approach to automatic change notification for related properties.

Tuesday, January 05, 2010 1:39:03 PM (W. Europe Standard Time, UTC+01:00)
Hi Jonas,

Your implementation has one problem.

Due to you are ignoring getter in the hook created dynamic proxies has no getters in reflection. That is why you wont be able to bind this properties.

In you project there is a sample application with MainPage.xaml. If you will try to set value of viewmodel properties (for example "Name") you will see that this value haven't been binded.

Best regards,
Alexey Zakharov.
Tuesday, January 12, 2010 3:08:18 PM (W. Europe Standard Time, UTC+01:00)
this.RaisePropertyChanged(() => this.City);

This works. But try it for Boolean properties, like:

this.RaisePropertyChanged(() => this.IsEnabled);

This doesn't work. Beacuase Booleans return "true" or "false" and not the Name when the Expression is run.

Besides that, the perf is not accepted at all. You get the same perf hit as described in this article (http://karlshifflett.wordpress.com/2009/08/02/inotifypropertychanged-how-to-remove-the-property-name-string-code-smell/) since you are still using Reflection inside the Expression method that resolves the propertyName. It is like calling directly MethodBase.GetCurrentMethod.Name.Remove(0, 4). So for me, the only acceptable way is to use the method introduced by Josh Smith in his MVVM Foundation library (tip: in debug mode it validates the propertyName).

Sometimes there has to be a clean separation between "design for performance" and "design for code reading".
Nikos Baxevanis
Saturday, January 16, 2010 3:02:14 AM (W. Europe Standard Time, UTC+01:00)
Alexey - thanks for pointing this out. I'll be sure to fix it for my next blog post. Working on integration with IoC and hope to have a post ready over the weekend.

Nikos: That depends on your implementation of RaisePropertyChanged. You can use reflection to parse the expression and get the name of the parameters being passed in, so this technique works just fine for booleans as well. Check out this blog post from Einar Ingebrigtsen for more info.

You are absolutely right about the perf. hit. However, do you really think a perf. hit of 0.44 to 3.7 milliseconds for 1001 change notifications is significant enough to keep strings floating around in the code?

A good solution would be if Microsoft introduced a nameof() operator in C# 5.0. So we could do: RaisePropertyChanged(nameof(Address)); just like we can do typeof(). This feature is registered as a suggestion on the Microsoft Connect site.

Thanks for commenting! :)
Sunday, January 17, 2010 10:44:47 AM (W. Europe Standard Time, UTC+01:00)
A perf. hit of 0.44 to 3.7 milliseconds for 1001 change notifications is significant if the code is going to be hit again and again. It adds presure to GC and it can be even worse:
Imagine if an object is going the get GC'ed: There is a dedicated thread that runs the code in the Finalize method. If some potential code cause this thread to enter an inifinite loop the thread blocks and now the object's memory won't be reclaimed. You will then leak memory and the application's working set could reach 200MB. This is from a real world scenario and i thought i should mention it. So untile nameof or some equivalent syntax-sugar comes up i will definetly use magic-strings in real world applications. At home i may use IAutoNotifyPropertyChanged or MethodBase.Xxx or Expressions. I can't wait to see Microsoft's implementation of MVVM in the future. Really! It's still 0.1 on codeplex WPFToolkit.
Cheers!
Nikos Baxevanis
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789