Animating margins in Silverlight
So I ran into a problem the other day where I needed to animate a margin of a control, but Silverlight doesn't allow for animating Thickness objects (WPF does). The solution I came up with is very simple and can be used to animate the Margin, Padding, or BorderThickness of any control. Since Silverlight doesn't support custom animations, we'll have to work with this hack for now.
1: using System;
2: using System.Net;
3: using System.Windows;
4: using System.Windows.Controls;
5: using System.Windows.Documents;
6: using System.Windows.Ink;
7: using System.Windows.Input;
8: using System.Windows.Media;
9: using System.Windows.Media.Animation;
10: using System.Windows.Shapes;
11:
12: namespace SLApp1
13: {
14: public class ThicknessAnimation
15: {
16: // The time along the animation from 0-1
17: public static DependencyProperty TimeProperty = DependencyProperty.RegisterAttached("Time", typeof(double), typeof(DoubleAnimation), new PropertyMetadata(OnTimeChanged));
18: // The object being animated
19: public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached("Target", typeof(DependencyObject), typeof(ThicknessAnimation), null);
20: // The thickness we're animating to
21: public static DependencyProperty FromProperty = DependencyProperty.RegisterAttached("From", typeof(Thickness), typeof(DependencyObject), null);
22: // The tickness we're animating from
23: public static DependencyProperty ToProperty = DependencyProperty.RegisterAttached("To", typeof(Thickness), typeof(DependencyObject), null);
24: // The target property to animate to. Should have a property type of Thickness
25: public static DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached("TargetProperty", typeof(DependencyProperty), typeof(DependencyObject), null);
26:
27: /// <summary>
28: /// Creates a Timeline used to animate the thickness of an object
29: /// </summary>
30: /// <param name="target">The object to animate</param>
31: /// <param name="targetProperty">The property on the object to animate</param>
32: /// <param name="duration">The length of the animation</param>
33: /// <param name="from">The begining thickness</param>
34: /// <param name="to">The final thickness</param>
35: /// <returns>A timeline object that can be added to a storyboard</returns>
36: public static Timeline Create(DependencyObject target, DependencyProperty targetProperty, Duration duration, Thickness from, Thickness to)
37: {
38: DoubleAnimation timeAnimation = new DoubleAnimation() { From = 0, To = 1, Duration = duration };
39: timeAnimation.SetValue(TargetProperty, target);
40: timeAnimation.SetValue(TargetPropertyProperty, targetProperty);
41: timeAnimation.SetValue(FromProperty, from);
42: timeAnimation.SetValue(ToProperty, to);
43: Storyboard.SetTargetProperty(timeAnimation, new PropertyPath("(ThicknessAnimation.Time)"));
44: Storyboard.SetTarget(timeAnimation, timeAnimation);
45: return timeAnimation;
46: }
47:
48: /// <summary>
49: /// Silverlight's animation system is animating time from 0 to 1. When time changes we update the thickness to be time
50: /// percent between from and to
51: /// </summary>
52: private static void OnTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
53: {
54: DoubleAnimation animation = (DoubleAnimation)sender;
55: double time = GetTime(animation);
56: Thickness from = (Thickness)sender.GetValue(FromProperty);
57: Thickness to = (Thickness)sender.GetValue(ToProperty);
58: DependencyProperty targetProperty = (DependencyProperty)sender.GetValue(TargetPropertyProperty);
59: DependencyObject target = (DependencyObject)sender.GetValue(TargetProperty);
60: target.SetValue(targetProperty, new Thickness((to.Left - from.Left) * time + from.Left,
61: (to.Top - from.Top) * time + from.Top,
62: (to.Right - from.Right) * time + from.Right,
63: (to.Bottom - from.Bottom) * time + from.Bottom));
64:
65: }
66:
67: public static double GetTime(DoubleAnimation animation)
68: {
69: return (double)animation.GetValue(TimeProperty);
70: }
71:
72: public static void SetTime(DoubleAnimation animation, double value)
73: {
74: animation.SetValue(TimeProperty, value);
75: }
76: }
77: }
To use this, simply call ThicknessAnimation.Create with the necessary parameters, add the timeline to a storyboard, and call storyboard.Begin()
Comments
- Anonymous
May 27, 2010
Hi,BenHow can i use the ThicknessAnimation in XAML tag? Thanks! - Anonymous
September 24, 2010
Can you post a example. I can't figure it out. The DependencyObject and DependencyProperty cause trouble. - Anonymous
November 27, 2010
Thanks for this great example of a ThicknessAnimation in Silverlight.I used this code (with a link back to this post) in my CodeProject article: <a href="www.codeproject.com/.../pandorasilverlight.aspx">Building a Pandora clone in Silverlight 4</a>. I used the ThicknessAnimation to animate song tiles into position.Great stuff. Thanks again. - Anonymous
November 27, 2010
*Link for that article: www.codeproject.com/.../pandorasilverlight.aspx - Anonymous
December 08, 2010
Thank you so much for this. It's fantastic and it works beautifully... I'd only recommend one thing, put a massive link to that article linked in the comments that shows how to use it with a concrete example. It took me a long time to get it to work and the example was the key.Thanks again. - Anonymous
January 24, 2011
Hey, although i didn't need a thickness animation, this is the example that led me to the right route, for my grid animation. The only difference being, mine is used from xaml and i think you could refactor it also for thickness. The example is in following post:http://www.run80.net/?p=84Thanks, hope this helps to some1! - Anonymous
May 26, 2011
I have refactored this code to be able to use set it in XAML www.microdivision.com/.../animating-thickness-and-margin-properties-in-silverlight