Master: Have you learned the scrolls of animation?
Student: Master, Yes studied them.
Master: Please tell me the what scrolls you consulted for your information?
Student: I went to the library and found information here:
http://msdn.microsoft.com/en-us/library/cc189019(VS.95).aspx
Master: Very good. What is animation?
Student: From the scroll above “Animation is a an illusion created by quickly cycling through a series of images.”
Master: What can be animated?
Student: You can animate properties of type Double , and Color.
Master: You missed the Point type.
Master: You have done well. Now listen as I explain today's lesson. Storyboards allow you to specify your animation sequence in XAML, and Blend is the tool of choice to rapidly create your animations. You can animate more properties than we can enumerate with these three types. Let us looks at an example of a ghosting effect for an element. Let us define a blue ball like so:
<Canvas Margin="216,126,305,235">
<Ellipse Fill="#FF0017FF" Stroke="Black" Height="119" Width="119"/>
<Ellipse Stroke="Black" Height="119" Width="119" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-127.913"/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Canvas>
We end up with something like this
Add a new storyboard and name it ghost. Create a copy of the. The XAML looks like this:
<Ellipse x:Name="blue_cp" Fill="#FF0017FF" Stroke="Black" Height="119" Width="119" />
<Ellipse x:Name="overlay_cp" Stroke="Black" Height="119" Width="119" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Visibility="Collapsed">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-127.913"/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
This is what we will use to create the ghosting effect. Here is the storyboard we created to gives us the ghosting effect:
<Storyboard x:Name="Ghost">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="00:00:01">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="00:00:01">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
What this does is in 1 second scale our copy objects by 3 and set the opacity to 0. This gives the effect of of the object growing bigger then vanishing. Lets attach an event handler to the first ellipse for MouseLeftButtonUP. We also wan to set the IsHitTestVisible to false for all other objects so we can capture the event with the object we want. IsHitTestVisible determines if an object participates in events to determine if an event has occurred on that object. The new xaml is below this is the entire control
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="animation.MainPage"
Width="640" Height="480" mc:Ignorable="d">
<UserControl.Resources>
<Storyboard x:Name="Ghost">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="00:00:01">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="00:00:01">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blue_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="overlay_cp" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="00:00:01" Value="3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Canvas Margin="216,126,305,235">
<Ellipse Fill="#FF0017FF" Stroke="Black" Height="119" Width="119" MouseLeftButtonUp="Ellipse_MouseLeftButtonUp" />
<Ellipse Stroke="Black" Height="119" Width="119" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" IsHitTestVisible="False" >
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-127.913"/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="blue_cp" Fill="#FF0017FF" Stroke="Black" Height="119" Width="119" RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
<Ellipse x:Name="overlay_cp" Stroke="Black" Height="119" Width="119" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" MouseLeftButtonUp="Ellipse_MouseLeftButtonUp" IsHitTestVisible="False">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-127.913"/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Canvas>
</Grid>
</UserControl>
The code behind looks like this
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace animation
{
public partial class MainPage : UserControl
{
public MainPage()
{
// Required to initialize variables
InitializeComponent();
}
private void Ellipse_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// TODO: Add event handler implementation here.
Ghost.Stop();
Ghost.Begin();
}
}
}
The above code will create a ghosting effect for a group of controls. So when the user clicks on the object it scales and animates to make it look like it gets bigger and the disappears.
I have two more blogs posts up and coming on is a how did they do that with particle clouds, and the other will be converting the ghosting storyboard to a behavior to attach to an UIElement.
Practice Hard and Happy Coding,
Master Bill Moore ;)
animation.rar (93.87 kb)