Silverlight Tip: Dynamic animations
Hello,
I was asked about creation of animations dynamically for various elements. Today I’ll show how to create such animations for any (almost) Silverlight element. I’ll create some of popular standard PowerPoint animations.
I know that it is not the full set of animations available in PowerPoint, also the animations itself are probably not perfect but it is a good starting point to those who want to know how to do it.
Generally, to create the animation on-the-fly we need to create a storyboard, add one or more animations to it, add the created storyboard to resources of our container and run it.
For this sample I’ve created function, which will receive Target Element, new storyboard name and some animation definitions. The function will add created storyboard to topmost parent element resources.
private void CreateAnimation(FrameworkElement targetElement,
string StoryboardName,
AnimationSpeed StoryboardDuration,
AnimationType type,
AnimationDirection direction)
{
//...
}
Also, I’ve created a couple Enums to define animation
private enum AnimationType
{
FlyIn,
FlyOut,
FadeIn,
FadeOut
}
private enum AnimationDirection
{
Top,
Bottom,
Right,
Left,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
None
}
private enum AnimationSpeed
{
ExtremlySlow = 10000,
VerySlow = 5000,
Slow = 3000,
Normal = 1000,
Fast = 500,
VeryFast = 250,
ExtrimlyFast = 100
}
In my “CreateAnimation” function I did the following:
1. Prepared TransformGroup with all possible Transforms for my desired element
private FrameworkElement prepareTransformGroup(FrameworkElement targetElement, Point transformOrigin)
{
targetElement.RenderTransform = new TransformGroup();
(targetElement.RenderTransform as TransformGroup).Children.Add(new ScaleTransform());
(targetElement.RenderTransform as TransformGroup).Children.Add(new SkewTransform());
(targetElement.RenderTransform as TransformGroup).Children.Add(new RotateTransform());
(targetElement.RenderTransform as TransformGroup).Children.Add(new TranslateTransform());
targetElement.RenderTransformOrigin = transformOrigin;
return targetElement;
}
2. Created new Duration object (based on received parameter) and Storyboard object
Duration duration = new Duration(TimeSpan.FromMilliseconds((double)StoryboardDuration));
Storyboard sb = new Storyboard();
sb.Duration = duration;
3. Then, based on direction, created animations (will see one of them – in my case other will be almost identical)
DoubleAnimation animX = new DoubleAnimation();
animX.Duration = duration;
FrameworkElement parent = GetParent(targetElement);
if (type == AnimationType.FlyIn)
animX.From = parent.ActualWidth * -SCALE_FACTOR;
else
animX.To = parent.ActualWidth * -SCALE_FACTOR;
animX.SetValue(Storyboard.TargetNameProperty, targetElement.Name);
Storyboard.SetTargetProperty(animX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
sb.Children.Add(animX);
DoubleAnimation animY = new DoubleAnimation();
animY.Duration = duration;
if (type == AnimationType.FlyIn)
animY.From = parent.ActualHeight * -SCALE_FACTOR;
else
animY.To = parent.ActualHeight * -SCALE_FACTOR;
animY.SetValue(Storyboard.TargetNameProperty, targetElement.Name);
Storyboard.SetTargetProperty(animY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"));
sb.Children.Add(animY);
4. Added created storyboard to topmost parent
FrameworkElement p = GetParent(targetElement);
p.Resources.Add(StoryboardName, sb);
5.GetParent function recursively traverses the visual tree until it gets topmost FrameworkElement
private FrameworkElement GetParent(FrameworkElement element)
{
if ((element.Parent as FrameworkElement) == null)
return element;
else
return GetParent((element.Parent as FrameworkElement));
}
Now we can call the “CreateAnimation” and then execute created animation
FrameworkElement elm = someButton;
if (null == ((LayoutRoot.Parent as FrameworkElement).Resources["myDynamicAnimation"] as Storyboard))
CreateAnimation(elm, "myDynamicAnimation", AnimationSpeed.Fast, AnimationType.FadeIn, AnimationDirection.None);
((LayoutRoot.Parent as FrameworkElement).Resources["myDynamicAnimation"] as Storyboard).Begin();
Here it works…
Dynamic Silverlight Animation
Full sources here.
Enjoy,
Alex