The other day I was hacking away in WPF and I decided that I needed to be able to do something specific when the Visibility property of a control changed. Now, as you probably know, most of the properties of WPF controls have an accompanying <PropertyName>Changed event, such as IsEnabled/IsEnabledChanged and (interestingly) IsVisible/IsVisibleChanged, but not (for some reason) Visibility.
So, these are just dependency properties and the whole point of dependency properties is change notification, so surely there's a way to find out when one has changed. As I often do when I'm stuck with WPF, I pinged my good friend and colleague Paul Jackson. Paul was busy but he pointed me in the right direction and a quick search later I'd found Ben Constable's post "Cool trick with Dependency Properties". What Ben describes is using the DependencyPropertyDescriptor class and the AddValueChanged method as shown in the following code example.
DependencyPropertyDescriptor descriptor =
These two lines of code create a DependencyPropertyDescriptor for the Visibility property of a panel named
hiddenPanel, and then add
hiddenPanel_VisibilityChanged as an event handler for when the value changes. Bingo! Problem solved. As it turned out, this isn't the approach I needed to take and I solved the problem in a different way as a result of understanding the problem space a bit better.
However, as with most things that Paul and I discuss, we opened a can of worms and had to dig a little further. As Paul points out in his post on the subject (he beat me to it!), there are two problems with this approach:
- You only supply an EventHandler to the AddValueChanged method, which means you don't get access to the previous and new values.
- You can get a memory leak with this solution unless you call the RemoveValueChanged method when you're all done. You can imagine that for more complicated scenarios, this could be more difficult.
As it turns out, Paul's digging turned up an article by the very clever Andrew Smith, which describes a complete solution to this problem using all of the elements that Paul had originally suggested would yield a full solution (the spelling mistakes are all his ;)):
(13:40) Paul Jackson:
So the downside to using the descriptor approach is that you do not get the "old" and "new" value information. So even though with only a couple of line of code you can get notified it's not that informative.
The alternative is also not that attractive, which is to use DataBinding: Create a DP of your own, with change notification enabled, then bind that property to the source that you really want notification for.
(13:43) Paul Jackson:
To clean this up, you could inherit from the target control and raise the necessary notifications by overriding the property metadata and calling your own event - sounds worse that it is, this is actually quite clean, and could with a little generics thrown in be an elegant solution (dunno yet as I have not tried).
(13:45) Paul Jackson:
Bottom line is that this version of WPF does not expose that information - It would be interesting to work out both how the descriptor mechanism and databinding mechanisms work to pull off the notifications (seeing as they appear to really only be internal to the owner of the DP)
If you look at Andrew's article, you can see that they are both very much "singing from the same hymn sheet." :)
At this point, I'd already proved that the original approach worked, used a completely different approach to solve my problem without resorting to dependency property change notification and moved on. However, Paul has blogged about the same problem and proposes his own solution that is "simple and easy to implement." So, if you need a solution to this problem, go and check out.