Custom TypeDescriptor and AddValueChange/OnValueChanged

249 views Asked by At

I’m exploring the use of custom TypeDescriptors to intercept when a data-bound property on a WPF control sets a CLR property. Due to reasons I need to figure out which exact control is setting a value.

If I use INotifyPropertyChanged I’ll get all of the different controls that subscribe to any property in my view model, not all that helpful. So I figured I’d go down the custom TypeDescriptor path and try the ProperyDescriptor.AddValueChanged and PropertyDescriptor.OnValueChanged way.

I can see that WPF calls ProperyDescriptor.AddValueChanged as expected, but my call to ProperyDescriptor.OnValueChanged never seems to trigger a call to PropertyDescriptor.GetValue and an update in the UI.

Are there some gotchas to using this stuff that I’m missing? Or are there other ways to figure out who’s subscribing to a CLR property. My alternative as I see it now would be to emit a custom proxy for the whole shebang, but I’d very much like to not have do that.

Edit: On looking at bit closer, I noticed that the delegates I get through PropertyDescriptor.AddValueChanged go to some internal MS helper class, so without some unreliable reflection-fu there's no way to use that to get the source control. I think I'll have to go with a custom proxy with dependency properties.

1

There are 1 answers

1
redcurry On

There's an alternative that may be useful. In a binding, you can set the NotifyOnSourceUpdated to True, which will raise the control's SourceUpdated event when WPF updates the CLR property it's data-bound to. For example, in a TextBox you can write:

<TextBox
    Text="{Binding MyText, NotifyOnSourceUpdated=True}"
    SourceUpdated="TextBox_OnSourceUpdated"
    />

In the code-behind, you can get the exact control (the sender) and the name of the dependency property that updated the CLR property:

private void TextBox_OnSourceUpdated(object sender, DataTransferEventArgs e)
{
    var control = (TextBox)sender;
    var propertyName = e.Property.Name;
}

With this method, you need to know that the control was a TextBox, but you can probably update it to test different kinds of controls. It depends on what you need this for, really.