A base class which implements INotifyPropertyChanged

The longer I’ve worked with WPF, the more implementations I have seen of the INotifyPropertyChanged interface. It’s everywhere. I have seen dozens upon dozens of classes all implement the interface separately, even though most of those classes descend directly from Object. This blog post examines the virtues of creating a base class which implements that interface, and deriving as many classes as possible from it.

Consolidating your implementation of INotifyPropertyChanged into a base class has several benefits.

You do not have to implement the same interface many times, which reduces the possibility of boredom (and programming errors…).

You can easily use cached instances of PropertyChangedEventArgs, to avoid fragmenting the managed heap with semantically identical instances.

You can easily use some reflection magic to verify that the property which allegedly changed actually exists (this is useful for debugging purposes, and is automatically turned off in Release builds).

You can override a method to execute logic which must run after a property is set.

I created an abstract class called BindableObject which implements INotifyPropertyChanged and provides all the goodies promised above. At the bottom of this post you can download the source code. Until then, let’s take a look at how it’s implemented.

Here’s the class from a high-level view:

As you can see above, classes which descend from BindableObject can call the RaisePropertyChanged method when one of their public properties is set to a new value. That will cause the INotifyPropertyChanged.PropertyChanged event to be raised so that the data binding system is alerted of the new value. If a child class wants to perform some processing after a property is set, it can override the AfterPropertyChanged method.

I made the class serializable in case you need it to be. The demo project does not make use of that aspect of the class. Now let’s take a look at the class’s protected members:

Now we’ll inspect the public members of BindableObject:

The main point of interest here is the GetPropertyChangedEventArgs method. It maintains a cache of PropertyChangedEventArgs instances, so that only one instance will exist for each property name passed through this class. This caching can dramatically reduce the managed heap fragmentation caused by a property being set many times in a short period of time. The reason I made GetPropertyChangedEventArgs public is so that any class can take advantage of its caching mechanism, even if the class does not descend from BindableObject.

In case you’re curious, here is how the property name is verified:

If a class which descends from BindableObject passes an invalid property name into the RaisePropertyChanged method, when the property is set this helpful assertion dialog will open:

Share this:

Like this:

LikeLoading...

Related

This entry was posted on Wednesday, August 29th, 2007 at 10:25 pm and is filed under Debugging, General Info, Praxis. You can follow any responses to this entry through the RSS 2.0 feed.
Both comments and pings are currently closed.

Post navigation

48 Responses to A base class which implements INotifyPropertyChanged

I just implemented this same class yesterday (but named it NotifyObject instead).
One extra feature I have is a BeginUpdate/EndUpdate so that I can do lots of updated and then trigger the events. I just put them all on a Queue if its updating, and trigger them all at EndUpdate.

Hi, excellent article on a common issue. I was wondering what the [field:NonSerialized] does? I’m assuming it prevents the event owner from serializing when the class is, is the correct? Do you know if there is a similar attribute for VB.Net? Sorry a little of topic, but when I don’t know something I NEED to ask.

Rogan,
There has been a lot of debate over whether business objects should descend from DependencyObject or not. I think its usually not necessary to do so because properties of BOs do not need the extra features provided by dependency properties. Working with DPs is more difficult than normal properties. Also, descending from DO ties your domain model classes to WPF, where using INotifyPropertyChanged does not.

Allan,
That attribute prevents the delegate field which the compiler emits to implement the PropertyChanged event from being serialized. Since a delegate internally stores hard references to its listeners, you need to prevent that delegate from being serialized. If the delegate were serialized then it would attempt to serialize the objects to which it points. The NonSerialized attribute, like all attributes, is not particular to C#. It can be used in VB as well.

if (!eventArgCache.TryGetValue(propertyName, out args)) // ContainsKey and indexer together
{
eventArgCache.Add(propertyName, args = new PropertyChangedEventArgs(propertyName)); // No need to get newly created args from dictionary
}
return args;

Do you have any managed heap fragmentation metrics or performance measurements to show that caching of PropertyChangedEventArgs is an important optimization?

I’m writing a financial services application which binds a dozen or so properties on a few hundred objects which get updated more than a thousand times a second during busy market times… So this seems like it could be a big deal for me.

I’m just curious if you had real measurements that show the scale of the benefit.

I’d also like to see your take on an implementation of Steve’s {Begin,End}Update pattern.

No I don’t have any tool which I use to measure the actual runtime benefits of caching event args. But, regardless of lacking empirical evidence, it just makes sense to do it. Creating a new PropertyChangedEventArgs instance every time a property changes is equivalent to feverishly shooting the managed heap with a shotgun.

I agree with your gut instinct on keeping heap fragmentation down, but being the performance geek that I am, I wrote a quick benchmark of the two methods. Retrieving the cached PropertyChangedEventArgs from the Dictionary is approximately 18X slower than creating a new one.

So I guess the question is how much is it worth to keep those tiny short lived objects out of the heap?

My benchmark created a billion of them in 6.9 seconds, but took 126 seconds to fetch the same one from the cache a billion times.

So that’s around 7ns to create one and 126ns to fetch one… but even at a kilohertz notification rate, it’s only the difference between 7us and 126us, which is in the noise so to speak. You’d have to be up around 80KHz notification rate to approach even 1% overhead.

Long story short, it can never hurt to frag the heap less and this method does not introduce a significant performance problem.

However, I have to agree with Patrick that using reflection here as the Base Class can significantly slow down your app if you have a lot of bindable fields to update. I’ve been to places where you need to update 200,000+ records per second on a regular basis and the speed of reflection just can’t keep up with it. Using the tedious and fast “boredom” implementation of INotifyPropertyChanged seems work ok in those data centric scenarios.

Patrick,
Thanks for the perf test. Did you use my code, or the optimized version which Steve left in a comment? I think creating a billion PropertyChangedEventArgs is rather intense, but I’m no expert in optimization techniques so I could be wrong.

Ligao101,
The code which uses reflection to verify that the property exists is removed by the compiler in a Release build. The [Conditional(“DEBUG”)] attribute prevents that code from existing or being called when in a Release build, so it’s not really a perf concern.

I just ran my own set of tests, creating a billion PropertyChangedEventArgs in a loop each time. Here are my results:

Without caching 00:00:35.1295902

With caching and no lock 00:02:04.3900344

With caching and lock 00:03:22.3161058

That lock certainly does affect performance, as Steve pointed out. Despite its negative impact on speed, I am hesitant to remove it seeing as how the eventargs caching method can be invoked from any thread at any time.

I’ve implemented a class very similar to this, and I had the same debate with myself about whether to inherit DependencyObject. A further consideration to add to those already mentioned is Threading. DependencyObjects, inheriting as they do from DispatcherObjects, are tied to the thread that created them. Only in the case of Freezables can they be moved to a different Thread.

I also have an INotifyPropertyChanged base class. One of the features I implemented was only notifying when the value had actually changed. (My app is essentially a huge graph of nodes that update in response to other nodes updating, so limiting notifications is valuable.) I implemented it like this.

Isn’t it risky to lock on the type? If anyone tries to lock on that type outside of your code, you just caused yourself a deadlock. While documenting it *could* be enough, I’m not a big fan of relying on developers reading the documentation… I’d have suggested a private static object syncRoot = new object() for your synchronization needs?

Otherwise very good post, everybody has had to write these base classes over and over again in WPF projects.

One last suggestion, there is a “feature” for PropertyChanged so that you can send string.Empty for when the object is completly changed, but with the current code it will break when trying to verify the property.

With respect to the performance metrics quoted. The one billion searchs for the same argument searched through how many items? I guess more to the point what is the search algo overhead? Is it linear? Is there a tipping point where the search algo is just too expensive regardless of the shotgun effect?

In general I think its going to be more of an individual decision based upon the developers application. But then again, isn’t everything. =)

Yeah, that’s what I was thinking about a few days after posting those results. The number of property names in the collection would definitely impact the performance. Unfortunately I’m not an expert at algorithm performance analysis, so my crude tests should be taken with a grain of salt. I’d love to read some “definitive” thoughts on the perf considerations for using this caching technique.

Ya know, now that I started adding this abstract class to my project I have noted that this only solves the problem for BOs. While that might have been ovbious to some of you it didn’t hit home until I tried to glue it to a few forms where I wanted the forms name to follow a BO’s name and as such properly update say a dropdown menu of active windows. Since ya can’t do that multiple inheritance thing I had to kill the abstract idea and use composition, so that I could encapsulate the event handler.

I implemented the same thing about 3 years ago, I even called it INotifyPropertyChange. I, however, retained a little more information regarding the property change such as the previous value, the value being set, and a means to cancel the modification.

[…] a class called ObservableFileInfo. That class is a FileInfo wrapper which descends from my BindableObject base class. It exposes a FileInfo property so that the UI can bind to the data about the file. When the […]

“In multithreading scenarios, do not lock Type objects in order to synchronize access to static (Shared in Visual Basic) data. Other code, over which you have no control, might also lock your class type. This might result in a deadlock. Intead, synchronize access to static data by locking a private static (Shared in Visual Basic) object.”

I commented on this thread a few months back and came across it again searching for information related to INotifyPropertyChanged and WPF DataBinding. As I said earlier, I have a LOT of objects that have a LOT of properties that get updated a LOT of times per second, those properties are DataBound to a LOT of xaml TextBlock’s full of converters and DataTriggers etc.

Needless to say I’m getting some performance lag for screen updates and was wondering if you had thoughts on how to possibly throttle, coalesce or otherwise mitigate the performance impact of this scenario. The ironic/classic situation is that everything works fine until there’s a major financial annoucement and the number of updates skyrockets… this of course is the MOST important time for my application to NOT lag behind realtime, and the only time it does… sigh…

[…] me that this might be simpler if I somehow make the state object inherit from something like a BindableObject (To implement the INotifyPropertyChanged stuff). This will have a huge performance boost because I […]

I’m not sure I see the benefit of caching PropertyChangedEventArgs. I don’t see any mention of the impact on the GC either. PropertyChangedEventArgs should be a short lived object and therefore should be collected in Gen 0 where collection is the fastest. You are now adding an object on the heap for every property in the object, not to mention promoting all of those objects into Gen 1 and most likely Gen 2.

I think you are all forgetting that all of the properties can be called from one class with one instance for all properties. The PropertyChangedEventArgs PropertyName property is Overridable. Therefore, we can do something like the following: (I am a vb person so sorry no c# although its cake to convert)

That’s an interesting idea. Your solution would not work in a multithreaded scenario, since multiple properties can be set “at the same time.” You’d need to use thread local storage, and have one PropertyChangedEventArg per thread.

I did not intend for the second class to be thread safe as it was just a simple example. To take care of the threading issue you can add a lock to OnPropertyChange to handle properties being changed from multiple threads.

FYI, I was porting this to Silverlight and had to remove the [Serializable] and [field: NonSerialized] attributes and Debug.Fail(msg) call to get it building. Guess you’d have to use WCF [DataContract] attribute instead and opt-in each member except for the EventHandler with [DataMember] attributes. Have you dealt w/ serialization of INotifyPropertyChanged objects in SL? Did you use the new WCF DataContractSerializer?

Also, in my solution, I’ve added in the DependsOn attribute and PropertyDependencyManager proposed by Tomas Elison in the comments here: