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.

  1. You do not have to implement the same interface many times, which reduces the possibility of boredom (and programming errors…).
  2. You can easily use cached instances of PropertyChangedEventArgs, to avoid fragmenting the managed heap with semantically identical instances.
  3. 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).
  4. 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:

BindableObject (class)

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:

BindableObject (protected)

Now we’ll inspect the public members of BindableObject:

 BindableObject (public)

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:

BindableObject (private)

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:

BindableObject (assertion)

Download the demo project here: BindableObject (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.

About these ads

48 Responses to A base class which implements INotifyPropertyChanged

  1. Steve says:

    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.

  2. Szymon says:

    Very helpful class. Thanks Josh!

  3. Rogan Josh says:

    Probably a bit of a noob question, but in what scenarios would it be better to derive from DependencyObject instead of a hand-rolled base class (which is cool – thanks!) such as this?

  4. Allan says:

    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.

  5. Josh Smith says:

    Steve,
    I like that idea! Sounds very useful.

    Szymon,
    Thanks.

    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.

    -Josh

  6. Steve says:

    And you can optimize the GetPropertyChangedEventArgs:

    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;

  7. Josh Smith says:

    Steve,

    That’s a good optimization. Thanks for posting it.

    Josh

  8. Patrick says:

    Josh,

    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.

    Thanks for sharing this code.

    -Patrick

  9. Josh Smith says:

    Patrick,

    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.

    Josh

  10. Patrick says:

    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.

  11. ligao101 says:

    Josh, this is an excellent post. Thanks for sharing it.

    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.

  12. Josh Smith says:

    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.

    -Josh

  13. Patrick says:

    I used Steve’s version.

    I only did a billion to get it to run for more than a second to call it a fair test! Here’s the method i used. The numbers I reported were from the Release build.

    public static PropertyChangedEventArgs GetPropertyChangedEventArgs(string propertyName)
    {
    if (String.IsNullOrEmpty(propertyName))
    throw new ArgumentException(“propertyName cannot be null or empty.”);
    PropertyChangedEventArgs args;
    lock (typeof(Test))
    {
    if (!eventArgCache.TryGetValue(propertyName, out args))
    {
    eventArgCache.Add(propertyName, args = new PropertyChangedEventArgs(propertyName));
    }
    }
    return args;
    }

  14. Josh Smith says:

    Patrick,

    Fair enough. :)

    Thanks for the detailed feedback and analysis.

    Josh

  15. ligao101 says:

    Josh,

    This is nice. Thanks for sharing this. I will try it out and see if can improve my current implementation without much performance impact :)

  16. Steve says:

    I’m guessing the lock will cause the most overhead, can you test it without using lock just to see the difference?

  17. Josh Smith says:

    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.

    Thoughts?

    Thanks,
    Josh

  18. Sam Jack says:

    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.

    My class, and Josh’s has no such limitations.

  19. 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.

    protected bool AssignAndNotify(ref T target, T value, params string[] properties) {
    if (!IsObjectEqual(target, value)) {
    target = value;
    System.Diagnostics.Debug.Assert(properties.Length > 0);
    foreach (string name in properties)
    SendPropertyChange(name);
    return true;
    }
    return false;
    }
    private static bool IsObjectEqual(T target, T value) {
    if (target == null)
    return value == null;
    // else
    return target.Equals(value);
    }
    private static bool IsObjectEqual(T target, T value) {
    if (target == null)
    return value == null;
    // else
    return target.Equals(value);
    }

    in my property setters I implement it like this
    private int prop;
    public int Prop{ set { AssignAndNotify(ref prop, value, “Prop”)}}

    I implement the name property as a params array so I can update multiple calculated properties with a single call.

  20. Josh Smith says:

    John,

    That seems like a very useful way to encourage sending proper change notifications. How well does it perform?

    Thanks,
    Josh

  21. Josh,

    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.

  22. Josh Smith says:

    Sebastien,

    That’s a good point about the lock. I had not thought of that, but agree that locking on the type is a bad idea.

    Thanks,
    Josh

  23. xiugraag says:

    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.

  24. Bryan Roth says:

    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. =)

  25. Josh Smith says:

    Bryan,

    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.

    Thanks,
    Josh

  26. Bryan Roth says:

    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.

  27. 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.

    Daniel

  28. [...] 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 [...]

  29. KierenH says:

    Josh,

    What if someone in another app-domain locks on BindableObject??

    “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.”

    http://msdn2.microsoft.com/en-us/library/system.type(VS.71).aspx

  30. Oran says:

    Another very cool way to do this is using an AOP tool such as PostSharp. They have a sample that lets you write code like this:

    [NotifyPropertyChanged]
    public class Wheel
    {

  31. Oran says:

    whoops, don’t try typing code in the comment box without looking!

    So to finish my comment,

    [NotifyPropertyChanged]
    public class Wheel
    {
    public bool IsBroken { get; set; }
    public int RotationAngle {get; set; }
    }

    that’s it. They also have an example that does this for IEditableObject.

    See this for details: http://doc.postsharp.org/index.html#http://doc.postsharp.org/UserGuide/Samples/PostSharp.Samples.Binding.html

  32. Josh Smith says:

    Thanks Oran, That looks really cool!

  33. Patrick says:

    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…

  34. Brent says:

    This is a very good post. I’m curious how you would use a class like this in Silverlight seeing as it does not include System.ComponentModel.INotifyPropertyChanged in its library.

  35. [...] 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 [...]

  36. Joe says:

    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)

    Imports System.ComponentModel

    Public Class ExtendedPropertyChangedEventArgs : Inherits PropertyChangedEventArgs

    Private basePropertyName As String

    Public Sub New(ByVal propertyName As String)
    MyBase.New(propertyName)
    Me.basePropertyName = propertyName
    End Sub

    Public Overrides ReadOnly Property PropertyName() As String

    Get
    Return Me.basePropertyName
    End Get

    End Property

    ‘this doesnt have to be write only as most properties are not, but easy enough to change
    Public WriteOnly Property InternalPropertyName() As String

    Set(ByVal value As String)
    Me.basePropertyName = value
    End Set

    End Property

    End Class

    ‘————————————————-
    ‘thats it for the base class, simple as cherry pie
    ‘————————————————-

    ‘—————————————————————————-
    ‘simple example class below, very, very simple, for explanation purposes only
    ‘—————————————————————————-

    Imports System.ComponentModel

    Public Class MyObject
    Implements INotifyPropertyChanged

    Private basePropOne As String
    Private basePropTwo As String
    Private basePropertyArgs As ExtendedPropertyChangedEventArgs

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Public Sub New()
    PropOne = “Foo”
    PropTwo = “Bar”
    End Sub

    Public Property PropOne() As String

    Get
    Return Me.basePropOne
    End Get

    Set(ByVal value As String)

    Me.basePropOne = value
    OnPropertyChange(“PropOne”)

    End Set

    End Property

    Public Property PropTwo() As String

    Get
    Return Me.basePropTwo
    End Get

    Set(ByVal value As String)

    Me.basePropTwo = value
    OnPropertyChange(“PropTwo”)

    End Set

    End Property

    Protected Sub OnPropertyChange(ByVal propertyName As String)

    If Me.basePropertyArgs Is Nothing Then
    Me.basePropertyArgs = New ExtendedPropertyChangedEventArgs(propertyName)
    Else
    Me.basePropertyArgs.InternalPropertyName = propertyName
    End If

    RaiseEvent PropertyChanged(Me, Me.basePropertyArgs)

    End Sub

    End Class

    And that does it, This has been my 2 cents.

    Thanks.

  37. Josh Smith says:

    Joe,

    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.

    Josh

  38. Joe says:

    Josh,

    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.

    -Joe

  39. [...] additional value to it, including a runtime check of property names in Debug builds (credits go to Josh Smith for this one). Just type inpc to print out this [...]

  40. John Rusk says:

    Hi Josh,

    You might like to check out the open source project that I’ve released here: http://www.codeplex.com/ActiveSharp

    It allows you to do property change notification without passing the property name as a string. This makes the code easier to write and safer to refactor.

    For instance, properties can be written like this

    public int Foo
    {
    get { return _foo;}
    set { SetValue(ref _foo, value);}
    }

    where SetValue is written like this, in the base class

    protected void SetValue(ref T field, T value)
    {
    PropertyInfo property =
    ActiveSharp.PropertyMapping.PropertyMap.GetProperty(this, ref field);
    field = value; // assign the value
    RaisePropertyChanged(property.Name); // your existing method
    }

  41. sublunary necrophagous dollhouse unrioting mutability euphemia gneiss extracivic
    Anything3D.com

    http://www.randburg.com/lv/history.html

  42. [...] d’un objet PropertyChangedEventArgs à chaque set de la propriété : Josh Smith mentionne dans un de ses posts que cette création de petits objets peut risquer de fragmenter la [...]

  43. Kevin says:

    Isn’t fragmentation of the managed heap impossible because the GC compacts memory?

  44. Josh Smith says:

    Kevin,

    The GC compacts memory because the managed heap becomes fragmented.

    Josh

  45. Patrick Parent says:

    It might not be useful, but for lazy programmer where performance is not needed.

    string propertyName = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name.Remove(0,4);

    You won’t have to type manually every parameterName, because it will get the parameter name inside the RaisePropertyChanded. You could already to an overload that takes a parameter name just in case.

  46. David Cuccia says:

    Hi again Josh,

    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:

    http://neilmosafi.blogspot.com/2008/07/is-inotifypropertychanged-anti-pattern.html

    Seems elegant…any thoughts?

    David

Follow

Get every new post delivered to your Inbox.

Join 289 other followers

%d bloggers like this: