Animation in XAML (Part 5)

November 29, 2013

Introduction

In this post, I would like to specifically focus on the differences between animations in WPF and in WinRT. Some quick disclaimers: As far as I’m aware, Windows Phone and WinRT are interchangeable where animations are concerned, but I base that only on my efforts to move a specific animation between the two. Consequently I won’t look at Windows Phone.

The Animation

Here’s a sample of the animation to cause the button to spin and disappear from previous posts:


         private void SpinAndDisappear\_Click( object sender, RoutedEventArgs e)
        {
           
            Button b = (Button)sender;
           
            DoubleAnimation da = new DoubleAnimation (b.Width, 0, TimeSpan.FromSeconds(.5));
            b.BeginAnimation( Button.WidthProperty, da);

            DoubleAnimation da2 = new DoubleAnimation (b.Height, 0, TimeSpan.FromSeconds(.5));
            b.BeginAnimation( Button.HeightProperty, da2);

            DoubleAnimation da3 = new DoubleAnimation (0, 360, TimeSpan.FromSeconds(.5));           
            RotateTransform transform = (RotateTransform )b.RenderTransform;
            transform.BeginAnimation( RotateTransform.AngleProperty, da3 );
        }

How it Works in WinRT

Okay, so the short answer is: it doesn’t - well, that doesn’t anyway! There are a few reasons why this won’t work in WinRT, but the most annoying one is that WinRT doesn’t support multiple animations on the same element. That is, only one storyboard can be running for a given element at any time.

Before we get into a workaround, so cunning, you could tie a tail to it and call it a fox, let’s look at the size animation in WinRT (as it’s not exactly the same); first the XAML:


             < Button x : Name="SpinAndDisappear" Content ="Don't press me" Click="SpinAndDisappear\_Click"
                RenderTransformOrigin ="0.5, 0.5" Height ="100" Width="300"/>

And the code behind:


             UIElement obj = ( UIElement)SpinAndDisappear;

            obj.RenderTransform = new CompositeTransform ();

            var story = new Storyboard ();

            var xAnim = new DoubleAnimation ();
            var yAnim = new DoubleAnimation ();           

            xAnim.Duration = TimeSpan.FromSeconds(2);
            yAnim.Duration = TimeSpan.FromSeconds(2);           

            xAnim.To = 0;
            yAnim.To = 0;
           
            story.Children.Add(xAnim);
            story.Children.Add(yAnim);

            Storyboard .SetTarget(xAnim, obj);
            Storyboard .SetTarget(yAnim, obj);

            Storyboard .SetTargetProperty(xAnim, "(UIElement.RenderTransform).(CompositeTransform.ScaleX)" );
            Storyboard .SetTargetProperty(yAnim, "(UIElement.RenderTransform).(CompositeTransform.ScaleY)" );
                      
            story.Begin();

I’ve borrowed quite heavily here from this article by Iris Classon:

http://irisclasson.com/2012/06/28/creating-a-scaletransform-animation-in-c-for-winrt-metro-apps/

Okay, so I want to execute two animations at the same time; surely I just do this:


         void SpinAnimation()
        {
            UIElement obj = ( UIElement)SpindAndDisappear;

            obj.RenderTransform = new RotateTransform ();
            var storySpin = new Storyboard ();
            var spinAnim = new DoubleAnimation ();
            spinAnim.Duration = TimeSpan.FromSeconds(2);
            spinAnim.From = 0;
            spinAnim.To = 360;
            storySpin.Children.Add(spinAnim);
            Storyboard .SetTarget(spinAnim, obj);
            Storyboard .SetTargetProperty(spinAnim, "(UIElement.RenderTransform).(RotateTranform.Angle)" );
           
            storySpin.Begin();
        }


And call SpinAnimation after the first StoryBegin()? That did work in WPF. If you do this, what you get is a rotation animation only. As stated before, one element, one animation. The workaround is ingenious and, unfortunately, not my idea:

http://stackoverflow.com/questions/20224307/running-multiple-animations-in-windows-store-app

But here’s how it looks:


         < Frame x : Name="SpindAndDisappearParent" Height ="100" Width ="300"
               RenderTransformOrigin ="0.5, 0.5">
            < Button x : Name="SpinAndDisappear" Content ="Don't press me"Click="SpinAndDisappear\_Click"
                RenderTransformOrigin ="0.5, 0.5" Height ="100" Width="300"/>

         


It’s important that the sizes of the parent and child elements are the same; next, just change the SpinAnimation() function like so:


         void SpinAnimation()
        {
            UIElement obj = ( UIElement)SpindAndDisappearParent;

            obj.RenderTransform = new RotateTransform ();
            var storySpin = new Storyboard ();
            var spinAnim = new DoubleAnimation ();
            spinAnim.Duration = TimeSpan.FromSeconds(2);
            spinAnim.From = 0;
            spinAnim.To = 360;
            storySpin.Children.Add(spinAnim);
            Storyboard .SetTarget(spinAnim, obj);
            Storyboard .SetTargetProperty(spinAnim, "(UIElement.RenderTransform).(RotateTranform.Angle)" );
           
            storySpin.Begin();
        } 

Conclusion

As you can see, I’ve rested heavily on the shoulders of giants here (which is another way of saying I’ve basically used other peoples code and ideas). Having said that, this area is virtually deserted as far as internet resources go; that’s why I started this series of articles in the first place.

Hopefully they’ve proved helpful.



Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2024