WPF FAQ - Animation

Find answers for the most frequently asked questions
Expand All Collapse All

WPF enables users to apply animations to objects by applying animations on properties. For a property to have animation capabilities, it should have the following requirements.

  • The property should be a dependency property.
  • It must belong to a class that inherits from the DependencyObject class and implements the IAnimatable interface.
  • There must be a compatible Animation type available for the property. For e.g. the Double type property can be animated using the DoubleAnimation. Similarly, the property to be animated should contain the corresponding animation type.
  • Permalink

    Note that in WPF all animations (element.BeginAnimation method) are executed asynchronously. So, if you call a bunch of BeginAnimation methods one after another in a for loop, they all will overlap and not really execute one after another.

    There is really no way to chain animations in WPF. You will have to basically listen to an animation’s Completed event and then trigger the next animation. To make such code efficient and scalable I came up with this recursion with in-line event handler based approach:

    Let us say you want to increase the width of these 2 rectangles one after the other via animation:

    [XAML]
    <Canvas>  
            <Rectangle x:Name='rect1' Canvas.Top='0' Width='30' Height='30' Fill='Aqua'></Rectangle>  
            <Rectangle x:Name='rect2' Canvas.Top='50' Width='30' Height='30'  Fill='Azure'></Rectangle>  
    </Canvas>  
    

    The code-behind for this would be:

    [C#]
    private void Window_Loaded(object sender, RoutedEventArgs e)   
            {   
      
                DoubleAnimation da = new DoubleAnimation(100, new Duration(TimeSpan.FromSeconds(3)));   
                List list = new List();   
                list.Add(new object[] { rect1, Rectangle.WidthProperty, da});   
                list.Add(new object[] { rect2, Rectangle.WidthProperty, da });   
      
                this.PerformAnimations(0, list);   
            }   
      
            private void PerformAnimations(int index, List lstDefinitions)   
            {   
                object[] definition = lstDefinitions[index] as object[];   
                AnimationTimeline animation = definition[2] as AnimationTimeline;   
                  animation.Completed += delegate  
                  {   
                      // Start the other animation after the end of the previous animation.   
                      index++;   
                      if (lstDefinitions.Count > index)   
                          this.PerformAnimations(index, lstDefinitions);   
                  };   
                  ((UIElement)definition[0]).BeginAnimation((DependencyProperty)definition[1], (AnimationTimeline)definition[2]);   
            }
    

    The idea is to maintain a list of ‘animation definitiions’ and execute animations from this list recursively.

    Permalink

    In code behind:

    The following article from MSDN describes how to Pause, Resume, Stop, etc. on a running animation:

    http://msdn.microsoft.com/en-us/library/ms741997.aspx

    In XAML:

    The following example uses controllable storyboard actions to interactively control a storyboard.

    [XAML]
    
    <Page xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
      xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
      WindowTitle='Controlling a Storyboard' >
      <StackPanel Margin='20' >
    
        <!-- This rectangle is animated. -->
        <Rectangle Name='myRectangle'
          Width='100' Height='20' Margin='12,0,0,5' Fill='#AA3333FF' HorizontalAlignment='Left' />
    
        <!-- This StackPanel contains all the Buttons. -->
        <StackPanel Orientation='Horizontal' Margin='0,30,0,0'>
    
          <Button Name='BeginButton'>Begin</Button>
          <Button Name='PauseButton'>Pause</Button>
          <Button Name='ResumeButton'>Resume</Button>
          <Button Name='SeekButton'>Seek</Button>
          <Button Name='SkipToFillButton'>Skip To Fill</Button>
          <Button Name='SetSpeedRatioButton'>Triple Speed</Button>
          <Button Name='StopButton'>Stop</Button>
    
          <StackPanel.Triggers>
    
            <!-- Begin the Storyboard -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='BeginButton'>
              <BeginStoryboard Name='MyBeginStoryboard'>
                <Storyboard >
                  <DoubleAnimation 
                    Storyboard.TargetName='myRectangle' 
                    Storyboard.TargetProperty='Width' 
                    Duration='0:0:5' From='100' To='500' />
                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
    
            <!-- Pause the Storyboard -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='PauseButton'>
              <PauseStoryboard BeginStoryboardName='MyBeginStoryboard' />
            </EventTrigger>
    
            <!-- Resume the Storyboard -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='ResumeButton'>
              <ResumeStoryboard BeginStoryboardName='MyBeginStoryboard' />
            </EventTrigger>
    
             <!-- Seek one second into the storyboard’s active period. -->
             <EventTrigger RoutedEvent='Button.Click' SourceName='SeekButton'>
               <SeekStoryboard 
                BeginStoryboardName='MyBeginStoryboard' 
                Offset='0:0:1' Origin='BeginTime' />
            </EventTrigger>   
    
            <!-- Skip to Fill -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='SkipToFillButton'>
              <SkipStoryboardToFill BeginStoryboardName='MyBeginStoryboard' />
            </EventTrigger>
    
            <!-- Stop the Storyboard -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='StopButton'>
              <StopStoryboard BeginStoryboardName='MyBeginStoryboard' />
            </EventTrigger>
    
            <!-- Triple the speed of the Storyboard -->
            <EventTrigger RoutedEvent='Button.Click' SourceName='SetSpeedRatioButton'>
              <SetStoryboardSpeedRatio SpeedRatio='3' BeginStoryboardName='MyBeginStoryboard' />
            </EventTrigger>
          </StackPanel.Triggers>
        </StackPanel>
      </StackPanel>
    </Page>
    
    Permalink

    Animations can be applied to the objects in WPF application when the data in the control changes using the DataTriggers. The following lines of code is used to apply animations using a DataTrigger

    [XAML]
    
    <TextBlock Text='WPF Application' Name='tb1' Foreground='Blue' FontSize='28' TextAlignment='Center' Height='50' VerticalAlignment='Top'>
    <TextBlock.Style>
          	<Style>
                <Style.Triggers>
    <DataTrigger Binding='{Binding ElementName=cb1,Path=IsChecked}' Value='true'>
                      <DataTrigger.EnterActions>
                      <BeginStoryboard>
                      <Storyboard>
    <DoubleAnimation Storyboard.TargetProperty='Opacity' From='0' To='1' Duration='0:0:1' AutoReverse='True' RepeatBehavior='Forever' />
                      </Storyboard>
                      </BeginStoryboard>
                      </DataTrigger.EnterActions>
                      <DataTrigger.ExitActions>
                      <BeginStoryboard> 
                      <Storyboard FillBehavior='Stop'>
    <DoubleAnimation Storyboard.TargetProperty='Opacity' To='1' Duration='0:0:1' />
                      </Storyboard>
                      </BeginStoryboard>  
    </DataTrigger.ExitActions>
    </DataTrigger>
    </Style.Triggers>
    </Style>
    </TextBlock.Style>
    </TextBlock>
    <CheckBox Name='cb1' Content='Show Animation' IsChecked='True' Height='30' HorizontalAlignment='Center' />
    
    Permalink

    The scenario is such that the animations in the page will continue to play until it is garbage collected, even when the page is navigated away to another page holding the memory and system resources for animation. There will be severe drop in performance when more animations are running in a page. To overcome this issue, ‘Unloaded’ event of the page can be used to remove the animations from the page such that the animations don’t consume memory and system resources.

    Permalink

    Animations can be applied without using the StoryBoard. BeginAnimation() method can be used to apply animations instead of StoryBoard. This method can be used when simple animations are applied to a property of a control.

    The following code snippet animates the width of the TextBlock using the ’BeginAnimation’ method.

    [C#]
    
    DoubleAnimation Dblanimation = new DoubleAnimation();
    Dblanimation.From = 25;
    Dblanimation.To = 50;
    Dblanimation.Duration = new Duration(TimeSpan.FromSeconds(3));
    tb.BeginAnimation(TextBlock.WidthProperty, Dblanimation);
    
    Permalink

    Share with

    Couldn't find the FAQs you're looking for?

    Please submit your question and answer.