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.
Category
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.
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.
PermalinkBy default, the value of the property on which the animation is applied is overwritten to the ’To’ value of the animation at the end of the animation. But, instead you can reset the property’s value to it’s original value by setting the ‘FillBehavior’ property of the animation to ‘Stop’ (by default it’s set to the HoldEnd enum).
PermalinkIn 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>
PermalinkAnimations 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' />
PermalinkThe 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.
PermalinkAnimations 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