WPF and Notifying Property Change
One of the central idioms of WPF development is having presentation tier classes implement the INotifyPropertyChanged interface. Anybody who has done more than a “Hello World” WPF application or two is almost certainly familiar with this and quite probably knows it like the back of his or her hand. As I’ve been learning WPF with C# over the past year (coming from a background of C++ and Java before that), my implementation of this has evolved a bit, and I thought I’d share the progression and my thoughts on why each subsequent implementation is an improvement.
By way of background, for anyone not familiar or looking for a refresher, this interface allows XAML bindings to keep in sync with the C# class. For instance, if you bound a XAML text box to a class property called “MyText”, the class containing MyText would implement INotifyPropertyChanged. This interface consists of just a single event, and properties fire the event when set. This is the mechanism by which the model (the thing being bound to) notifies the GUI that it should ask for an updated value. Without this, the GUI would display whatever value MyText had when it was loaded, and it would ignore subsequent changes that came from anywhere but the user modifying the text.
Here is literally the simplest implementation possible of INotifyPropertyChanged:
public class Model : INotifyPropertyChanged
{
//This is all that the interface requires
public event PropertyChangedEventHandler PropertyChanged;
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
if(PropertyChanged != null)
PropertyChange(this, new PropertyChangedEventArgs("Text"));
}
}
}
So, whenever anyone (GUI or other code) invokes the setter for the Text field, the model class fires this event to notify the GUI (or anyone else listening) that the model’s Text has been changed. A popular, slight improvement on this would be to check that the value has actually been changed (that _text != value) before doing the setting or firing the event. The idea here is to prevent spurious event firing and thus spurious event handling.
The Basic Improvement
The first thing anybody is going to notice after implementing a few properties to back the UI is that each property setter requires an annoying amount of boilerplate. So, any Pragmatic Programmer would find a solution that didn’t involve all of this repetition–abstracting the boilerplate into a common method:
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(PropertyChangedEventArgs e)
{
if(PropertyChanged != null)
PropertyChange(this, e);
}
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyChange(new PropertyChangedEventArgs("Text"));
}
}
}
Clearly, this is better. You’ve eliminated two lines of code and a conditional from property setters. Amortized over an application, this will make the code more readable, more succinct, and easier to reason about.
What about all of those news
The next thing that will probably occur to someone after working with this for a while (or at least it did to me), is that it might not be necessary to create the same object every time a property is set. And that’s really what’s happening–you’re creating a new PropertyChangedEventArgs(), which is handed over to any event handler and then (probably) subsequently discarded. If you have a strange case in which someone is keeping that change event args around, then you can disregard this next optimization, though you might want to inquire why someone is storing that piece of communication artifice rather than whatever it may contain.
So the next solution I was introduced to (I didn’t actually come up with this on my own because I tend to be rather sparing in my use of “static”) is the following:
public class Model : INotifyPropertyChanged
{
private void NotifyChange(PropertyChangedEventArgs e)
{
if(PropertyChanged != null)
PropertyChange(this, e);
}
private string _text;
private static PropertyChangedEventArgs _textArgs = new PropertyChangedEventArgs("Text");
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyChange(_textArgs);
}
}
}
Here, we’ve cut further down on the boilerplate in the setters, but, more importantly, we’re not allocating new objects on the heap with each property that’s set. Instead, there’s a static object initialized at application startup. You pay a one-time cost at startup, and then everything is much more efficient after that.
Tweaking the Optimization
After being shown this technique and using it for a while, I felt increasingly like something wasn’t quite right and there was room for improvement. Eventually, I put my fingers on two minor gripes. First, the property changed args were being created at application startup, for every property, whether or not anyone ever set it. Pedantically (though sometimes practically), this is not as efficient as it could be. It’s an improvement over creating on every set, but not as good as creating it the first time you need it. The second thing that bothered me is all of the boilerplate that went along with it. In the first step, we eliminated some boilerplate, and now, we’ve added it back into the mix. Instead of in our setter, it sits above our property.
To counter those two issues, I added a base class from which models (and ViewModels, if they expose properties directly) should inherit. If you don’t like a common ancestor like that, you could always implement this with an interface and a default behavior extension method on that interface, but I’m not a fan of extension methods for ‘extending’ your own code in your own assembly (extension methods just being syntactic sugar on free-floating static methods)
public abstract class ModelBase : INotifyPropertyChanged
{
private readonly Dictionary<string, PropertyChangedEventArgs> _argsCache =
new Dictionary<string, PropertyChangedEventArgs>();
protected virtual void NotifyChange(string propertyName)
{
if (_argsCache != null)
{
if (!_ArgsCache.ContainsKey(propertyName))
_argsCache[propertyName] = new PropertyChangedEventArgs(propertyName);
NotifyChange(_argsCache[propertyName]);
}
}
private void NotifyChange(PropertyChangedEventArgs e)
{
if(PropertyChanged != null)
PropertyChanged(this, e);
}
}
public class Model : ModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyChange("Text");
}
}
}
What’s going on here is that we maintain a cache of EventArgs. Whenever a property change notification fires, the cache is checked for the corresponding event arguments. If they don’t exist, you new them up, but if they do, then this behaves like our static one. The end effect is that, for the life of the object, you get the benefit from the previous example of a single creation and the additional benefit of not taking a huge hit at application startup for all (and some potentially unneeded) properties. This suffers, performance wise, if you implement it on a lot of short lived models, because you might then, in effect, be newing all the time. The tradeoff is probably worth it if you have a high ratio of model modification to model creation. In my case, I do.
What About Those Magic Strings?
If you’re like me, the presence of “Text” everywhere in this set of examples has been like a little pebble stuck in your shoe. It’s annoying enough to irritate, but not necessarily quite annoying enough to fix at the moment. However, continuing the silly metaphor, you eventually hit your breaking point, wrench off your shoe, and do something about it. With the magic strings, that came a few months back.
I poked around on the internet some and saw various people’s solutions to this. None of them were quite to my liking, so I cobbled together one of my own from assorted pieces and my own style of coding. I don’t have any links because I honestly don’t recall where I found them and which parts would be attributable to whom. So, just be aware that not all of the thinking was entirely from scratch and that if you find somebody’s code that looks, in part, like this, there’s a good chance that’s where I got part of the idea.
public abstract class ModelBase : INotifyPropertyChanged
{
private readonly Dictionary _argsCache = new Dictionary();
protected virtual void NotifyChange<T>(Expression<Func<T>>propertySelector)
{
var myName = GetMemberName<T>(propertySelector);
if (!string.IsNullOrEmpty(myName))
NotifyChange(myName);
}
protected virtual void NotifyChange(string propertyName)
{
if (_argsCache != null)
{
if (!_argsCache.ContainsKey(propertyName))
_argsCache[propertyName] = new PropertyChangedEventArgs(propertyName);
NotifyChange(_argsCache[propertyName]);
}
}
private void NotifyChange(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
public class Model : ModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyChange(() => Text);
}
}
}
This is a lot more involved, and I won’t go into all of the gory details here. But, suffice it to say, I’m taking advantage of a concept called early binding. The “automagic” way that WPF binds its XAML to your properties is through reflection in the framework. It sees {Binding Text} and it goes looking on the data context for a property called “Text”. When it finds that, it invokes ToString() on it, and that’s what appears in the GUI. For notifying change, the same thing happens. It takes “Text” from your event args and goes looking for a match in the XAML.
This is called “late binding.” You are trusting at runtime that the WPF runtime is going to be able to match your two constructs through reflection. A typo, “text” instead of “Text”, for instance, will not stop the application from building or event trigger a compiler warning. The IDE is perfectly happy to let you make as many of these mistakes as you can manage. It won’t even throw a runtime exception. You’ll just get weird results and have to pick through the output window looking for XAML problems (or painstakingly match your XAML to your Notification arguments).
With Early binding, we eliminate that. The expression that you’re passing to NotifyChange() is typesafe and compiler-checked. This means that you need to pass it an actual property or it will not compile. Now, it’s possible that you’re going to have a “Text” and a “Txet” or “text” property, but it’s not very likely, and, if you do, you may want to reconsider your naming schemes. Since you’re now binding your notification to its property at build time rather than using reflective indirection through the WPF framework, you’re a lot less prone to mistakes.
I should point out here that you are introducing extra reflection, which means you’ll take a bit of a performance hit. However, I’ve never found it to be noticeable (I have never done a time trial on it, though), and I think the tradeoff in whatever performance hit you take is well worth the hours, days, and weeks you don’t lose to tracking down obscure typos in XAML or property notifications months after they happen. Besides, the WPF framework relies heavily on reflection anyway, so you’re just adding to the paradigm slightly. If you’re using WPF, you’re probably not logging your response times in microseconds anyway.
Conclusion
So, that’s it. That’s the evolution of how I notify the GUI that things have changed. If you have a suggestion for improvement, I’d be happy to add another step to the mix. I’m always looking to improve and find slicker, more elegant ways to do things.
By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.
Nice site, nice and easy on the eyes and great content too.
Thanks — glad you enjoyed.
Excellent thoughts
Glad you liked it.
You have really interesting blog, keep up posting such informative posts!
Nice example, good progression for learning but I have one question. How is it that in your last example ModelBase did not need to implement the INotifyPropertyChanged interface? Thanks
Hi Rick,
Thanks for reading and for your feedback.
You are absolutely right, ModelBase does need to implement INotifyPropertyChanged. I made an error in transcription — ModelBase should have continued to implement INotifyPropertyChanged. I will make the correction. 🙂
Great post. Really helpful.
However, there’s a tiny mistake. In the first four snippets, this:
if(PropertyChanged != null)
PropertyChange(this, e);
Should be
if(PropertyChanged != null) PropertyChanged(this, e);There’s a missing ‘d’ when calling the method. Fifth snippet is correct.
Thanks.
I made the change accordingly — good catch.
Thanks for getting the pebble out of my shoe.
Glad if it helped! =)
Use CallerMemberName instead of an expression. https://msdn.microsoft.com/en-us/library/hh534540.aspx?f=255&MSPPError=-2147217396
Dear Erik,
Hope all is well my friend, I was looking for some WPF info and I came across this article by chance and was pleasantly surprise to see your picture, very nice article Thanks.
Hi Parviz — good to hear from you! Glad if this helped you with your WPF needs.
Just curious….where is the GetMemberName method?
Wow, for the life of me, I’m not sure. Got lost somewhere in the interceding 6 years or so, I guess. Probably moot now, as well, with CallerMemberName and nameof() as first class parts of the language. Still, that’s weird — I have no recollection of where that code was in the examples I created at the time. Perhaps I just omitted that method when copying the class to the post.