DarksideCookie

Come to the dark side...we have cookies!

Cool INotifyPropertyChanged implementation

While working on a little MVVM thingy the other day, I ran into a sweet little piece of code that I wanted to share. I have seen several version of this around the web, but this is where I found this particular version. The piece of code gets rid of the ugly part of the INotifyPropertyChanged interface. The part where you use strings to identify what property has changed. I understand that that is how you have to do it, but it feels messy. A common solution is to add constants to hold the strings, but that is not a very much better solution. it is still messy. So how can we handle it in a safe way? Well…one idea would be to do it like this…

public class ViewModelBase : INotifyPropertyChanged
{
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}

protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression.Body.NodeType == ExpressionType.MemberAccess)
{
var memberExpr = propertyExpression.Body as MemberExpression;
string propertyName = memberExpr.Member.Name;
this.RaisePropertyChanged(propertyName);
}
}

public event PropertyChangedEventHandler PropertyChanged;
}

 

Instead of passing a string straight off, you use an Expression. This makes it safe. The way to call this would be like this: RaisePropertyChanged(() => MyProperty). Very elegant in my mind. The only issue would be that there is a lot of reflection going on, so it will be a lot slower. But to be honest, that is not a big problem in this case. It is not like it is something that will be called inside a loop with millions of iterations. At least it shouldn’t be…

Well…that was it. Just a simple little tip that I thought might be useful.

 

[UPDATE]

As there are a lot of comments regarding the performance implications of this implementation, I just want to make a little update.

First of all, for all the comments regarding IL emit and cool things like that, I just want to say that the idea with code is to keep it simple and precise. Your code should have a single responsibility. Adding IL emit code to your properties is wrong (at least in most cases, I have more about that later). And on top of that, you can’t do IL emit on Windows Phone 7 for example. So by using features like that, you are limiting your code reuse.

Next, I would like to ask if there really are performance issues here!? Let’s take a pretty common scenario. The user clicks a button, a command is called, the command executes some code that changes 2 properties that cause 2 property changed notifications. Those two notifications causes the UI to render something else on the screen. So with all of this happening (code executing, UI re-rendering and so on), will the property notification be the biggest problem? I actually don’t think so, I think that part of it is so small that you can ignore it. For the performance for different notification implementations, have a look here: http://www.pochet.net/blog/2010/06/25/inotifypropertychanged-implementations-an-overview/

Having that said, I do agree with the guy in the blog above. There are scenarios where you need to think about the performance. But that is not in you usual situation. It is in situations like live graphs and things like that, where you raise 200 notifications a second. In a scenario like that, of course you need to look at the performance. But in a normal VM scenario, you really don’t… And even in the extreme scenarios, I would probably try a coupe of different solutions to see how much they affected the performance.

And finally I want to remind some of you of the simple, yet very effective KISS pattern. Keep It Simple Stupid… Or even YAGNI, You Ain’t Gonna Need It. This is a perfect situation to start using those “patterns”. I do think that keeping it simple in the case of INotifyPropertyChanged would mean just using strings like normal, but let’s ignore that since you are going to need non string based functionality in a lot of cases. You are however not going to need the last bit of performance in most situations. So KISS and YAGNI basically tells us that we don’t need anything more complicated than the above code…at least that is how I interpret it.

Posted: Jun 15 2010, 07:09 by ZeroKoll | Comments (12) |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: Silverlight | WPF
Manage post: :)

Comments (12) -

Tim Haughton United Kingdom said:

Having used something similar before, I think it is/was slower. Dr WPF's snippets make it too simple for me to worry about these days Smile

# June 15 2010, 13:51

Will United States said:

Been using t4 more and more for boilerplate crap like this.  Got a wicked little template that generates code to implement custom type descriptors based on this post:  http://www.scottlogic.co.uk/blog/colin/2009/08/declarative-dependency-property-definition-with-t4-dte/ wouldn't take much to tweak it in order to automatically generate INPC properties.

ReCaptcha words:  "Mucus Appreciation"  Awesome.

# June 15 2010, 14:29

Joe Wood United States said:

This is great, but the performance is going to be a big problem.
One way to tackle that would be to dynamically generate a function for each unique call.  The IL.Emit would do the reflection only once, with each subsequent call checking a hashtable to see if the dynamically generated function had been generated or not and calling it accordingly.

# June 15 2010, 16:34

Manuel Felício Portugal said:

Thanks for the feedback.

When dealing with fairly complex MVVM scenarios you will find yourself raising PropertyChanged more often than just simple INPC Get/Set properties. Thats why its useful to have a safe way to raise the event. CodeSnippets or Code Generators are a great help, but they don't cover all scenarios.

Anyway, its nice to see people caring about this stuff.

Happy coding,

MF.

# June 16 2010, 00:26

Jeff Handley United States said:

This seems to be pretty common... I've recommending that people move away from having this Expression code buried in RaisePropertyChanged though, and keep with a string for that method, using a Member.Of(() => MyProperty) call to convert an expression to a string.

Check it out here:
http://jeffhandley.com/archive/2010/04/10/memberof.aspx

# June 16 2010, 07:34

Tau Sick Denmark said:

This is what they use in the latest prism4 drop. I used regular expressions to change all my RaisePropertyChanged to lambda.

It is slower at runtime because of reflection, but you could make a clever build event that changed it all back prior to a release?

This is how I replaced all existing calls to use the lambda:

http://www.clr-namespace.com/post/MagicStringInRaisePropertyChanged.aspx

# June 16 2010, 08:11

ZeroKoll New Zealand said:

Thanks for all the feedback. I do know that this is not something new or revolutionary and probably even a common way of doing it. But I still liked it and still wanted to highlight it.
I do however want to add some comments for all the people saying that they do this using T4 or such. There are just situations where a T4 template will not quite cut it. How will your template know that property A should also raise a INPC event for property B? That logic has to come from somewhere. So however you do it, you will need to write something. On top of that, I do not want to add INPC code to all my properties. There is no reason to in a lot of cases. So that will require custom logic as well...
As for the performance of doing it this way... Well, i do know that this is slow...very slow...but most of the time you change a property here and a property there, you don't change 100000 properties at once. So performance in this case should not be a problem...
I like the idea of IL.Emit, but once again the performance is not going to be a problem in 99.99% of the cases. I promise!
Why make the code complicated to fix something that probably won't be a problem. Only add measures like this when actually face the problem. Most of the time, performance problems will occur in places where you do not expect it.
That's my opinion at least...

# June 17 2010, 23:15

Manuel Felício Portugal said:

100% agreed. I wouldn't have said better.

# June 18 2010, 11:31

ZeroKoll New Zealand said:

Joe...read my comment regarding performance...
and on top of that, IL.Emit isn't available when building for Windows Phone 7, so that won't work on that platform. So for code re-use, I wouldn't use it. But that's me...

# June 19 2010, 04:14

Colin E. United Kingdom said:

@Will and others. I have updated the T4 template approach I blogged about for creating dependency properties. It now 'automates' and codesnippet, allowing you to apply them to a class using attributes:

http://www.scottlogic.co.uk/blog/colin/2011/04/viewmodel-inotifypropertychanged-code-generation/

The example in this blog post also covers how you handle dependent properties, i.e. a change in property A also changes property B.

Enjoy!

Regards, Colin E.

# April 21 2011, 17:05

Rick O'Shea United States said:

Remember "premature optimization is the root of all evil". The use of reflection here is intuitively inconsequential, however, if sleep loss ensues you can always measure it as part of your general load/performance testing. Where this might be important is fat object creation(the number of properties in the object graph is large).

# June 26 2011, 18:36

Kevin Frei United States said:

I built & timed the hashtable cache lookup, and if you do it properly/safely (with a ReaderWriterLockSlim to handle multiple thread access), it's actually slower than the normal Linq Expression stuff here.  Turns out that hashes are kinda slow to generate Smile

The () => {} Action trick that you can find elsewhere is MUCH faster, but relies upon 2 things that aren't guaranteed/documented.  The first is the name of the lambda function generated, and the second somewhat related, though much more 'near & dear' to me is that it assumes that the compiler isn't going to coalesce lambdas.  I'm currently funding a project to do just that, in the hopes that I can convince the C#/VB compiler teams to run it as a post-past if someone compiles with extreme optimizations.

# January 18 2012, 08:04

Pingbacks and trackbacks (1)+

Comments are closed