Home > Mobile >  Set NotifyOnTargetUpdated for existing binding
Set NotifyOnTargetUpdated for existing binding

Time:09-24

I have a binding in xaml <TextBlock Style="{StaticResource textStyle}" Text="{Binding DisplayText}" />.

I am attempting to write an attached behavior that reacts to the bound DisplayText value changing. If I specify NotifyOnTargetUpdated=True in the xaml, I can react to the change within the behavior and everything is fine, but I'd rather not depend on binding the Text property in a specific way just to make the behavior work.

My thought was to change the NotifyOnTargetUpdated value on the existing TextBlock.TextProperty binding when the behavior is opted in. I am using the below code to do so, where tb is the TextBlock being opted in.

var textBinding = BindingOperations.GetBinding(tb, TextBlock.TextProperty);
textBinding.NotifyOnTargetUpdated = true;
tb.SetBinding(TextBlock.TextProperty, textBinding);

The behavior is opted in like so, in the style: <Setter Property="behaviors:Text.AutoSizeText" Value="True"/>

Initially this didn't work because textBinding was null. I can get around this by binding the Text property in xaml before the behavior property, but this still leaves an external dependency that I don't like (xaml ordering). If I do go this route, I get the below exception, which seems to indicate that I can't accomplish this in this way, at all.

InvalidOperationException: Binding cannot be changed after it has been used.

So then, how can I go about automatically handling setting NotifyOnTargetUpdated for the Text binding when the behavior is opted in?

CodePudding user response:

I was able to solve my problem thanks to direction provided by @canton7. I was originally (as is often the case) looking for the way to implement my imagined solution, rather than a solution that fit my need. After adjusting my outlook, my working solution is thus:

Add the AttachedProperty InternalText to the behavior class, with a property changed handler.

private static readonly DependencyProperty InternalTextProperty = DependencyProperty.RegisterAttached(
            "InternalText", typeof(string), typeof(Text), new PropertyMetadata(default(string), HandleInternalTextChanged));

In the changed handler (HandleInternalTextChanged above) do the work that I would have done in a TargetUpdated handler if my original idea to set NotifyOnTargetUpdated had worked out.

On opt-in to my behavior, create a binding from the opted-in TextBlock.Text to the InternalText attached property.

var internalBinding = new Binding { Source = tb, Path = new PropertyPath(TextBlock.TextProperty) };
tb.SetBinding(InternalTextProperty, internalBinding);

The HandleInternalTextChanged callback on InternalTextProperty allows me to work around being unable to change the NotifyOnTargetUpdated value by providing an alternate means of notifying on each change.

CodePudding user response:

I prefer to bind internally to DisplayText because I'd prefer to bind to the source, if possible, rather than daisy-chain through the TextBlock.Text property.

If you need a binding to a source property, then it is created in a slightly different way.

    var binding =  BindingOperations.GetBindingBase(tb, TextBox.TextProperty);
    if (binding == null)
    {
        tb.ClearValue(InternalTextProperty);
    }
    else
    {
        tb.SetBinding(InternalTextProperty, binding);
    }
  • Related