I’ve been meaning to write about this for a while since I’ve seen this approach mentioned lots of times on the newsgroups but have seen no mentions about the caveats. Just today I saw the same problem in some code from one of the disciples. The scenario is that you want to know when the value of a dependency property changes but you don’t have a one to one relationship with the object. For example, you have a list of items and you want to know when the IsSelected property of an item has changed.
The solution that I have seen given for this is to get to the PropertyDescriptor and use its AddValueChanged method to provide an EventHandler to receive a notification when the property has changed. Sometimes, the reply will mention/use DependencyPropertyDescriptor directly but its the same thing since that is just a derived PropertyDescriptor that provides additional information about the underlying DependencyProperty it represents. You can get to this property descriptor in a few ways but the most common are to get it from the TypeDescriptor.GetProperties method or using the DependencyPropertyDescriptor.FromProperty.
The issue with this approach is that it will root your object so it will never get collected by the GC. There have been plenty of discussions about how hooking events (particularly static events) can root your object so I won’t go into great detail there. While it does not seem that you are hooking a static event in this case, in essence you are. When you add a handler to a property descriptor, that property descriptor stores the delegate in a hashtable keyed by the object whose property you are hooking. A delegate/handler is basically a pointer to a method on an object (or no object if its for a static method) so that means the property descriptor has a reference to your object as well as the object whose value you are watching (since that is the key into the hashtable). The property descriptors themselves are cached statically so the hashtable is kept around and therefore your object and the one you are watching are as well.
I personally like to use the Scitech memory profiler (or you can use the Microsoft CLR Profiler) when debugging memory leak issues but you can see the issue manifest itself pretty easily in this case. First we’ll do a benchmark to make sure that we can check whether the object was collected.
If you run this code and check isAlive, you will see that it returns false indicating that the ListBoxItem was not referenced and was able to be collected. Now let’s try using the AddValueChanged method.
This time isAlive returns true because the property descriptor is maintaining a reference to the ListBoxItem. Now, let’s try an alternative approach that involves creating a helper class to listen for the property change.
In this case isAlive is false indicating that the object can be collected even though we’re still maintaining an explicit reference to the notifier. The implementation for the class – PropertyChangeNotifier – is listed below. The class is basically a simple DependencyObject that exposes 2 properties – Value returns the value of the property of the object that it is watching and PropertySource returns the object whose property it is watching. The constructor for the object takes the object whose property is to be watched for changes and the property that should be watched. This class takes advantage of the fact that bindings use weak references to manage associations so the class will not root the object who property changes it is watching. It also uses a WeakReference to maintain a reference to the object whose property it is watching without rooting that object. In this way, you can maintain a collection of these objects so that you can unhook the property change later without worrying about that collection rooting the object whose values you are watching.
Another possible approach would be to implement your own derived WeakEventManager but I’ll leave that as an exercise for the reader. For those that choose to go this route, there is such a class – except its internal – in the PresentationFramework assembly.
April 9, 2008 at 5:55 am |
Andrew,
Very nice! Thank you for sharing this solution.
Cheers,
Karl
April 9, 2008 at 12:22 pm |
Nice solution, Andrew. I like how you use Binding’s internal weakref in this case. Very cool!
One question for you…does the memory leak still exist if you call RemoveValueChanged on the property descriptor? Does that remove the entry from the internal hashtable?
Thanks,
Josh
April 9, 2008 at 12:44 pm |
No, it won’t leak memory if you remove the handler. When the last handler is removed, the item is removed from the hashtable. But if you’re relying on say an item being removed from the collection before you remove the handler, that may not happen – e.g. if you just close the form while the list is populated. In that case, you might be able to also unhook within the Unloaded event but then you have to know to re-hook again should your element get reloaded (e.g. if the element is in a tab control and you switch to another tab and back).
April 9, 2008 at 12:49 pm |
Thanks. That makes sense.
August 26, 2008 at 1:21 pm |
Hi Andrew,
Thanks for this great article! It really helped a lot with cleaning up the code I am working on currently.
I have been using WeakEventManager class with some other events but I have not been able to come up with a way to use it with DependencyPropertyDescriptor.
The reason being, the way you attach the event in weakeventmanager is
source.<> = DeliverEvent;
I am not able to fit DependencyPropertyDescripter into that structure.
Please let me know if you have any suggestions.
August 26, 2008 at 1:21 pm |
Correction to my above comment
The reason being, the way you attach the event in weakeventmanager is
source.Event += DeliverEvent;
August 26, 2008 at 2:00 pm |
Thanks. I’m glad it helped.
If you look at the internal ValueChangedEventManager class in the PresentationFramework assembly (which is what MS is using for this) you can see that they are using a custom class (ValueChangedRecord) to add a handler for the property changed of the PD and that class has a reference back to the WeakEventManager (and the listenerlist) and uses the manager’s DeliverEventToList method instead of the DeliverEvent method.
December 3, 2008 at 3:57 pm |
Hey Andrew, I had been looking all day for a replacement for WPF’s DependencyPropertyDescriptor and I came across this article. Unfortunately it looks like they removed the Bindable() attribute from the final Silverlight release – do you have an update to this code that works in the final bits?
Thanks,
Bob
February 23, 2009 at 10:15 am |
If you change this line
if (null != notifier.ValueChanged)
notifier.ValueChanged(notifier, EventArgs.Empty);
to this, you will get the correct sender in the event
if (null != notifier.ValueChanged)
notifier.ValueChanged(notifier.PropertySource, EventArgs.Empty);
February 23, 2009 at 10:18 am |
If you are just replacing the AddValueChanged to use this, remember you will need a reference to the notifier, the previous way (DependencyPropertyDescriptor) did as it has an internal hash map. maybe save someone a few minutes
July 16, 2010 at 8:22 am |
[…] man sich ein MemoryLeak in den Code. Wer das ganze einmal genauer nachlesen will dem sei folgender Post von Adrew Smith ans Herz gelegt. Ich habe den Code einfach übenommen. Die eigentliche Logik ob das […]
October 13, 2010 at 10:28 am |
You sir, are my HERO
November 11, 2010 at 7:13 am |
Want to say about DependencyPropertyDescriptor.AddValueChanged in composition with an WeakEventManager pattern.
As you say, the DependencyPropertyDescriptor.AddValueChanged method roots not only our event handler, but the event source object.
So with WeakEventManager the event handler can be collected, but the event source remains rooted without call to WeakEventManager RemoveListener(where the RemoveValueChanged need to be called).
Imagine the situation where the event handler target and the event source is the same objects? The call to RemoveListener(RemoveValueChanged) is mandatory again.
An WeakEventManager approach is pointless with AddValueChanged.
November 11, 2010 at 7:33 am |
[…] Оригинальное решение для AddValueChanged: https://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/ […]
November 14, 2010 at 12:17 pm |
I have added a PinToSource(true by default) option to your PropertyChangeNotifier class, that forces it action more like regular weak event, just subscribe to an event and forget.
In the background, it makes two things, the ValueChanged event becomes weak, and the PropertyChangeNotifier pins himself to an event source object by reference through attached property.
The code is at code.google.com/p/sovetnikov/source/browse/WPFLib/Misc/WeakEventHelper.cs
November 17, 2010 at 5:38 am |
Thanks a lot, Andrew!
I was considering using the “DependencyPropertyDescriptor.AddValueChanged()” approach when I encountered this article. Saved me from a lot of trouble! Great insight into WPF!
February 23, 2011 at 1:05 pm |
Thanks for this article!!!! I was using AddValueChanged which was causing a leak. Your class solved it for me 🙂
May 4, 2011 at 9:19 am |
Nice one. It’s always amazing how many little of these GC “hooks” are lurking inside the WPF framework. Thank god for the SciTech and RedGate memory profilers, or http://www.Qiqqa.com would be dead in the water 🙂
One suggestion is that I would recommend that instead of passing in the property name as a string (because it makes refactoring a nightmare), that you remove that constructor and always use the DependencyProperty…
Thanks again for the post!
Jimme
July 3, 2011 at 10:52 am |
[…] PropertyDescriptor AddValueChanged Alternative […]
August 8, 2011 at 11:53 am |
I don’t understand the logic. Now we have leek of instance PropertyChangeNotifier instead of ListBox. Is it better?
September 11, 2011 at 3:39 am |
Why is the Dispose method needed here? What if I just keep PropertyNotifier objects in a list and casually remove objects with null PropertySource? Do I really need to call the Dispose method before removing them from the list in that scenario?
October 26, 2011 at 8:29 am |
[…] WPF handles these sort of problems internally by a vast sprinkling of the Weak Event Design Pattern, and mostly leaves you to fend for yourself when it has caused you to bump against these “by design” memory leaks. How should you fight this evil? Well, my personal recommendation is to avoid using AddValueChanged entirely, and instead use the PropertyChangedNotifier class from Andrew Smith’s blog post. […]
March 6, 2012 at 3:42 pm |
Price Comparison…
[…]PropertyDescriptor AddValueChanged Alternative « Andrew Smith[…]…
March 9, 2012 at 2:10 pm |
nice one…
[…]PropertyDescriptor AddValueChanged Alternative « Andrew Smith[…]…
May 2, 2012 at 9:41 am |
csa standards…
[…]PropertyDescriptor AddValueChanged Alternative « Andrew Smith[…]…
November 4, 2012 at 4:20 pm |
Wow, a really nice solution. I have seen this one on the web:
http://bjorn.kuiper.nu/2011/05/11/tips-tricks-listening-to-dependency-property-change-notifications-of-a-given-element/
but you cannot re-register the handler for another instance of your watcher. The solution above works not only in WPF & Silverlight but also with multiple registrations / instances. Very nicely done! 🙂
November 27, 2012 at 12:24 am |
Thanks Andrew!!
Its works for me !!!!!
January 16, 2013 at 4:34 pm |
This is really the 4th blog, of yours I personally went through.
Nevertheless I love this particular one, “PropertyDescriptor AddValueChanged Alternative Andrew Smith” the very best.
All the best ,Christopher
January 17, 2013 at 4:13 pm |
What really encouraged you to create “PropertyDescriptor AddValueChanged
Alternative Andrew Smith”? I actuallyhonestly appreciated it!
Thanks for your time ,Star
February 17, 2013 at 8:51 pm |
@ jon – thank you for the tip about keeping a reference to the notifier, you really helped me! I couldn’t figure out why the event would fire once but then wouldn’t fire after that. I guess the notifier was being cleaned up once it went out of scope since I wasn’t keeping any reference to it. Now that I hold a reference to it the even seems to fire every time it’s supposed to.
March 14, 2013 at 7:39 am |
[…] fix the above memory leak, you can use a wonderful solution that was posted online, in 2008, by Andrew Smith. It leverages the fact that the binding mechanism […]
June 26, 2013 at 9:54 pm |
hello, Mes parents m’ont appellée Marphisa et j’aime beaucoup ce
prénom.
Je suis agée de trente-cinq ans Et tant pis si on ne le dit pas .
Mon métier: fleuriste … Il est dit que je suis une bonne poire.
August 14, 2013 at 3:43 pm |
Thank you so much, this was causing us such a problem.
The weird thing was, that we WERE calling RemoveValueChanged – but it simply wasn’t working – not that I can find any reference on the internet anywhere that RemoveValueChanged can fail to do its job.
We were calling AddValueChanged in the Loaded, and RemoveValueChanged in the Unloaded – I checked they were both called, both the correct numbers of times.
Even more strangely, we had 2 situations in which the control was Unloaded – one where we were merely switching between tabs in a tabcontrol (both with different datatemplates, hence control unloading), and another where the tabcontrol itself was unloading as well. Our RemoveValueChanged appeared to work when the tabcontrol was unloading, but didn’t work when just moving between tabs of the tabcontrol.
It bothers me that I was not able to fully understand what the problem was with our calling of RemoveValueChanged, but your solution has fixed our memory leak. Thanks again.
August 19, 2013 at 10:39 am |
People often stay away from the portable audio system fearing that
they’ll lack the audio quality. The choices endless when you happen to be dealing with home audio speakers which are wireless and good quality. Some wireless systems have the ability to transmit full 1080p high-definition signals.
March 4, 2015 at 12:05 am |
[…] PropertyDescriptor AddValueChanged Alternative […]
December 31, 2015 at 1:04 pm |
It’s awesome in favor of me to have a web page,which iis valuable
for mmy know-how. thanks admin
February 24, 2016 at 2:54 pm |
Falls das Baby ständig an die Brust will, sollte man sich keine Sorgendarüber machen, daß es nicht satt wird.
May 23, 2016 at 10:57 am |
The code and the explanation of the WPF property and event handler interaction here is excellent.
May I ask though – what is the license on the code presented in this blog post, if any?
June 5, 2016 at 11:37 am |
Sorry for not replying sooner. As to the license, it isn’t under any particular license but feel free to use the code in this post however you need it.
June 5, 2016 at 1:17 pm
Thank you for the clarification.
May 25, 2016 at 8:10 pm |
Lecker, ausgewogen, zielgruppengerecht, von Kindern und Jugendlichen akzeptiert und wirtschaftlich – so soll Kita- und Schulverpflegung sein.
June 13, 2016 at 8:14 am |
Great solution, Thanks 🙂
June 13, 2016 at 10:13 am |
I was glad too soon 😦 , I don’t know why it doesn’t call the event:
PropertyChangeNotifier columnWidthChangedNotifier = new PropertyChangeNotifier(column, “ActualHeaderWidth”);
columnWidthChangedNotifier.ValueChanged += new EventHandler(OnColumnWidthChanged);
I’m calling it for all my columns and when I change the width of my column it doesn’t raise the event.
Any help will be appreciated.
Thanks,
Chen
June 14, 2016 at 11:08 pm |
Zwar musst Du in der Schwangerschaft nicht die doppelte Menge essen, aber Du solltest Dich jetzt ausgewogen und gesund ernähren.
June 24, 2016 at 10:39 pm |
Mehrere Studien haben belegt, dass langsames essen schneller zur Sättigung führt.
June 28, 2016 at 10:38 am |
Jürgen R. aus München (16.11.2014): Ich bekomme seit 12.11.14
gegen erhöhten Blutdruck Ramipril 5 mg. Hätte aber gerne etwas aus der Natur.
September 26, 2016 at 5:28 am |
Why ValueChanged call only once?
Asked before by @JK.
October 10, 2016 at 1:54 am |
[…] WPF handles these sort of problems internally by a vast sprinkling of the Weak Event Design Pattern, and mostly leaves you to fend for yourself when it has caused you to bump against these “by design” memory leaks. How should you fight this evil? Well, my personal recommendation is to avoid using AddValueChanged entirely, and instead use thePropertyChangedNotifier class from Andrew Smith’s blog post. […]
January 4, 2018 at 3:00 am |
I have checked your website and i’ve found some duplicate content, that’s why you don’t rank high in google, but there is a tool that can help you to create 100% unique articles, search for:
Boorfe’s tips unlimited content
March 7, 2018 at 7:04 pm |
Schöne Homepage 🙂
February 5, 2019 at 12:26 pm |
Your place is valueble for me. Thanks!…
October 12, 2019 at 5:21 am |
[…] a project written in VB.net I want to use the PropertyChangeNotifier class from this article, at least I’d like to try if it can […]
February 24, 2020 at 7:12 am |
[…] WPF handles these sort of problems internally by a vast sprinkling of the Weak Event Design Pattern, and mostly leaves you to fend for yourself when it has caused you to bump against these “by design” memory leaks. How should you fight this evil? Well, my personal recommendation is to avoid using AddValueChanged entirely, and instead use thePropertyChangedNotifier class from Andrew Smith’s blog post. […]
November 18, 2020 at 1:59 am |
[…] WPF handles these sort of problems internally by a vast sprinkling of the Weak Event Design Pattern, and mostly leaves you to fend for yourself when it has caused you to bump against these “by design” memory leaks. How should you fight this evil? Well, my personal recommendation is to avoid using AddValueChanged entirely, and instead use thePropertyChangedNotifier class from Andrew Smith’s blog post. […]
February 5, 2022 at 8:54 pm |
[…] PropertyChangedNotifier is a basic function that is often needed in WPF to know when a DependencyProperty changed, as implemented here. […]
March 7, 2022 at 4:51 pm |
[…] of dependency property descriptor results in memory leak as you already know. So, as described here, you can create custom class PropertyChangeNotifier to listen to any dependency property […]