Using data binding to launch animations in WPF

11,617

Solution 1

I had the opportunity to put this question to Microsoft's Josh Twist, who kindly took the time to provide an answer to this problem. The solution is to use a DataTrigger in combination with an enum in the ViewModel to launch the Storyboard, and this in turn requires putting the page into a ContentPresenter. To handle animation completion, a small amount of code behind was required to make a call into an ICommand on the ViewModel.

Read Josh's post here for a full description of the solution.

Solution 2

I did this by a using DataTrigger and binding it to a property in my ViewModel. When the "FlashingBackGround" property gets set to "ON" the Storyboard animation starts.

Also make sure to include in your project a reference to "Microsoft.Expression.Interactions"

XAML: (this goes directly in the root node)

<Window
   xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
   xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
   x:Name="window" >
    ...

    <i:Interaction.Triggers>
      <ei:DataTrigger Binding="{Binding FlashingBackground, Mode=OneWay}" Value="ON">
        <ei:ControlStoryboardAction Storyboard="{StaticResource MyAnimation}"     
                                                ControlStoryboardOption="Play"/>
      </ei:DataTrigger>
    </i:Interaction.Triggers>

    ...
</Window>

ViewModel:

    private void TurnOnFlashingBackround()
    {
        this.FlashingBackground = "ON";
    }

    private string _FlashingBackround = "OFF";

    public string FlashingBackground
    {
        get { return this._FlashingBackround; }

        private set
        {
            if (this.FlashingBackground == value)
            {
                return;
            }

            this._FlashingBackround = value;
            this.OnPropertyChanged("FlashingBackground");
        }
    }

    public new event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(
                this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }

Finally, the Viewmodel must inherit from "INotifyPropertyChanged"

Solution 3

You need to use an EventTrigger. This article about Animations in WPF might help. See also the Routed Events Overview on the MSDN and How to: Use Event Triggers to Control a Storyboard After It Starts.

Share:
11,617
Mark Heath
Author by

Mark Heath

I'm the creator of NAudio, an open source audio library for .NET. I'm interested in any ways to improve the quality of my code, and teaching others the things I learn along the way. I'm also the author of several Pluralsight courses.

Updated on July 25, 2022

Comments

  • Mark Heath
    Mark Heath almost 2 years

    I am trying to adapt a simple WPF application to use the Model-View-ViewModel pattern. On my page I have a couple of animations:

    <Page.Resources>
        <Storyboard x:Name="storyboardRight"
                    x:Key="storyboardRight">
            <DoubleAnimation x:Name="da3"
                             Storyboard.TargetName="labelRight"
                             Storyboard.TargetProperty="Opacity"
                             From="0"
                             To="1"
                             Duration="0:0:0.5" />
            <DoubleAnimation x:Name="da4"
                             Storyboard.TargetName="labelRight"
                             Storyboard.TargetProperty="Opacity"
                             From="1"
                             To="0"
                             BeginTime="0:0:1"
                             Duration="0:0:0.5" />
        </Storyboard>
        ...
    </Page.Resources>
    

    Currently I begin the animation in the code behind, and can listen to the Completed event to do something when it finishes with the following code:

    storyboardRight = (Storyboard)TryFindResource("storyboardRight");
    storyboardRight.Completed += new EventHandler(storyboardRight_Completed);
    storyboardRight.Begin(this);
    

    Is there a way of data binding the storyboard to my ViewModel so that it starts on an event raised by the ViewModel and can call-back into that ViewModel when it is finished?

  • Mark Heath
    Mark Heath over 15 years
    thanks for the pointer, but all the docs for EventTrigger show it being triggered by an event coming off an existing FrameworkElement. I am now firing a RoutedEvent from my ViewModel but can't see how to get the XAML to subscribe: <EventTrigger RoutedEvent="my:NumbersViewModel.RightAnswer">
  • eFloh
    eFloh almost 13 years
    Also note: you need two assembly references: System.Windows.Interactivity and the above mentioned Microsoft.Expression.Interactions.
  • Nathan Phillips
    Nathan Phillips over 11 years
    This solution only requires putting the page into a CpntentPresenter if you use a DataTemplate. It is possible to use it in a control's own style's triggers rather than the DataTemplate's triggers if you are animating properties of the control.
  • Simon Gillbee
    Simon Gillbee about 10 years
    The link to Josh Twists site is broken. Apparently Josh's entire site is broke (no blog articles load) and when I try emailing him it just bounces. Anyone know how to contact Josh and remedy the situation?
  • Mark Heath
    Mark Heath about 10 years
    @SimonGillbee I've sent him a message on twitter