Search code examples
wpfevent-handlingeventsmultibinding

Why does Multibinding have NotifyOnTargetUpdated but no TargetUpdated property


I've run into a problem where the TargetUpdated event seemed like it would be perfect. Unfortunately it looks like Multibinding does not have a TargetUpdated property. Is there some way to still set this up or do I need to find another solution entirely.

Heres some code to help

Heres the binding...

<RotateTransform x:Name="LeftNeedle">
<RotateTransform.Angle>
    <MultiBinding Converter="{StaticResource VoltageRatioConverter}" NotifyOnTargetUpdated="True" >
        <Binding ElementName="root" Path="Running" />
        <Binding ElementName="root" Path="Incoming" />
    </MultiBinding>
</RotateTransform.Angle>

Then I have the value converter...

public class VoltageRatioConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values == null || values.Count((x) => x != null) != 2)
            return 0.0;

        double running = System.Convert.ToDouble(values[0]);
        double incoming = System.Convert.ToDouble(values[1]);

        return ((running / incoming) - 1);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

And what I'm looking to do is retrieve that resulting number and pass it to a function to update the angle/animation

    private static void OnAngleValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        GaugeCluster gauge = o as GaugeCluster;
        if ((double)e.NewValue > 70)
        {
            VisualStateManager.GoToState(gauge, "RightWobble", false);
        }
        else if ((double)e.NewValue < -70)
        {
            VisualStateManager.GoToState(gauge, "LeftWobble", false);
        }
        else
        {
            if ((double)e.OldValue > 70 || (double)e.OldValue < -70)
            {
                VisualStateManager.GoToState(gauge, "StandingState", false);
            }
        }
    }

^ This function I was just testing to make sure that it actually worked by making it a callback from one of the two dependency properties. Ideally the function body is what I want to use on the TargetUpdated event.


Solution

  • TargetUpdated is an attached event. You register for this event on the binding target, not the binding itself :

    <RotateTransform x:Name="LeftNeedle" Binding.TargetUpdated="LeftNeedle_TargetUpdated">
        <RotateTransform.Angle>
            <MultiBinding Converter="{StaticResource VoltageRatioConverter}" NotifyOnTargetUpdated="True" >
                <Binding ElementName="root" Path="Running" />
                <Binding ElementName="root" Path="Incoming" />
            </MultiBinding>
        </RotateTransform.Angle>
    </RotateTransform>
    

    UPDATE: Actually the solution above doesn't work because RotateTransform is not a UIElement... You need to handle the Binding.TargetUpdated event on the UIElement to which it is applied :

    <Rectangle Fill="Blue" Width="30" Height="30"
               Binding.TargetUpdated="LeftNeedle_TargetUpdated">
      <Rectangle.RenderTransform>
        <RotateTransform x:Name="LeftNeedle">
            <RotateTransform.Angle>
                <MultiBinding Converter="{StaticResource VoltageRatioConverter}" NotifyOnTargetUpdated="True" >
                    <Binding ElementName="root" Path="Running" />
                    <Binding ElementName="root" Path="Incoming" />
                </MultiBinding>
            </RotateTransform.Angle>
        </RotateTransform>
      </Rectangle.RenderTransform>
    </Rectangle />
    

    The event will bubble up to the Rectangle, and you can check the TargetObject property of the event args to check if it is the rotation