Search code examples
wpfbindingsliderdependency-propertieswpf-animation

Animation and 2-way binding


I'm playing with WPF animation and faced a weird problem.

I have a Slider and a TextBox. TextBox is bound to Slider.Value using 2-way binding:

<StackPanel>
    <Slider x:Name="MySlider" Minimum="0" Maximum="100" Value="50" />
    <TextBox Text="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}" />
    <Button Click="Button_Click">Test</Button>
</StackPanel>

When I drag slider, text in textbox changes. When I change text in textbox, value of slider is updated, it works correctly.

Now I add an animation, which animates Slider.Value property to 0. I start it on button press.

private void Button_Click(object sender, RoutedEventArgs e)
{
    Storyboard storyboard = new Storyboard();
    var animation = new DoubleAnimation();

    animation.Duration = new Duration(TimeSpan.FromSeconds(0.5));
    animation.To = 0;

    Storyboard.SetTarget(animation, MySlider);
    Storyboard.SetTargetProperty(animation, new PropertyPath(Slider.ValueProperty));

    storyboard.Children.Add(animation);
     
    storyboard.Begin();
}

When I press button, animation scrolls Slider to 0. TextBox is also changes to 0 synchronously with slider.

And now I face the problem. After animation I cannot change text in the TextBox. I change text, move focus, and the text with slider value resets to 0. I still can move the Slider, and the TextBox updates with the Slider value. But I can't set the Slider value using the TextBox.

I think when animation stops, the value somehow freezes on a value, specified in the animation.To property, but I can't figure how to unfreeze it. Or maybe it is something else?


Solution

  • It happens because of dependency property value precedence, meaning that value set by animation has higher "priority" than value set via binding.

    Here is a quote from MSDN on how to workaround this:

    One way to regain control of an animated property in code is to use the BeginAnimation method and specify null for the AnimationTimeline parameter. For more information and an example, see How to: Set a Property After Animating It with a Storyboard.