Monthly Archives: November 2013

Animation in XAML (Part 5)

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"/>

         </ Frame>

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.

Animation in XAML (Part 4)

Introduction

Following on from http://pmichaelsdev.wordpress.com/2013/11/18/animation-in-xaml-part-3/ this post is about achieving the simultaneous effect of spinning and disappearing. I thought I’d also use it to list a few other animations and how to achieve them. They’re all variations on a theme to be honest, but I’ll try to list as many as may be useful.

A word of note: most of the animations will be on buttons, but I’m not aware of any restrictions as to the target (it can be any UI Element). Also, the code listed is all based on a button event; again, this can be any event that makes sense… or even one that doesn’t. For example; try the spin and disappear on MouseOver!

Spin And Disappear

Code behind:

             Button b = (Button)SpinAndDisappear;
           
            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 );

XAML:

         <Button x:Name="SpinAndDisappear" ...
                RenderTransformOrigin="0.5, 0.5">           
           
            <Button.RenderTransform>
               
                 <RotateTransform>
               
                 </RotateTransform>
            </Button.RenderTransform>
               </Button>

Fade

Code behind:

             Button b = ( Button)Fade;

            DoubleAnimation da = new DoubleAnimation (b.Opacity, 0, TimeSpan.FromSeconds(.5));
            b.BeginAnimation(Button.OpacityProperty, da);


Highlight The Current Textbox (Border Animation)

This is a nice little effect: when the user hovers the mouse over the textbox, the border is animated to make it stand out.

XAML:

             <TextBox Width ="300" Height="50" x:Name ="border" MouseEnter="border_MouseEnter"
                     MouseLeave="border_MouseLeave">
               
            </TextBox>

Code behind:

         private void border_MouseEnter( object sender, RoutedEventArgs e)
        {
            TextBox t = ( TextBox)border;
            ThicknessAnimation ta = new ThicknessAnimation (new Thickness (3), TimeSpan.FromSeconds(.3));
            t.BeginAnimation( TextBox.BorderThicknessProperty, ta);
        }

        private void border_MouseLeave( object sender, MouseEventArgs e)
        {
            TextBox t = ( TextBox)border;
            ThicknessAnimation ta = new ThicknessAnimation (new Thickness (1), TimeSpan.FromSeconds(.3));
            t.BeginAnimation( TextBox.BorderThicknessProperty, ta);

        }

As a minor (and obvious caveat): make sure that the starting width is the same as that on MouseLeave.

Conclusion

That’s all the animations and effects that I could think of. If you know of, or can come up with any more then if you eitjer add them in the comments, or contact me (www.twitter.com/paul_michaels or pcm2605@hotmail.co.uk) and I’ll add them in.

In the next (and final) post, I’ll focus on the differences in WinRT / Windows Phone 8.

Animation in XAML (Part 3)

Introduction

In this article, I’m going to expand on the first posts, by providing an alternative way to chain animations. In this article http://pmichaelsdev.wordpress.com/2013/10/29/animation-in-xaml-part-1/, I showed how to use the BeginTime property to do this; and that works fine; however, I did come across, what appeared to me to be, a slightly more elegant way of doing this: events.

Just for the sake of being different, I’ll use a different animation

Using Events to Chain Animations in WPF

Let’s start by creating a button that spins when you click it. The code isn’t too dis-similar to that in Part 1. Let’s have a look at the XAML first:


         <Button x:Name="SpinAndDisappear" Width="200" Height="50" Content ="Don't press me" Click="SpinAndDisappear_Click"
                RenderTransformOrigin="0.5, 0.5">
            <Button.RenderTransform>
                <RotateTransform/>
            </Button.RenderTransform>
        </Button>

Two things to note here: The RenderTransformOrigin will make it spin round the centre. Remove that and it’ll spin round the top left corner (and that would be just silly); and the RotateTransform section. That has to be there in order for WPF to know it can rotate the button.

Okay, here’s the code to spin the button:

         private void SpinAndDisappear_Click( object sender, RoutedEventArgs e)
        {
            Storyboard spin = (Storyboard )FindResource("sbSpin");
            spin.Begin( this);

        }

If you’ve been paying close attention, you’ll notice that this won’t work (even without running it and getting an error saying it can’t find the storyboard!). Here’s what the storyboard should look like:

    <Window.Resources >
        <Storyboard x:Key="sbSpin">
            <DoubleAnimation
              Storyboard.TargetName="SpinAndDisappear"
              Storyboard.TargetProperty="(Button.RenderTransform).(RotateTransform.Angle)"
              From="0"
              To="360"
              Duration="0:0:3" />
        </Storyboard>
    </Window.Resources >

That’s better, try that and you’ll have a spinning button.

Okay, so it spins. It’s not that impressive to be honest. Lets add another effect to the storyboard to make it more impressive (the clue to what that will be is in the name of the button). Let’s create that effect now:

     <Window.Resources>;
        <Storyboard x :Key="sbDisappear">
            <DoubleAnimation
                Storyboard.TargetName="SpinAndDisappear2"
                           Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleX)"
                           From="1" To ="0" Duration="0:0:0.2"/>
            <DoubleAnimation
                Storyboard.TargetName="SpinAndDisappear2"
                           Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleY)"
                           From="1" To ="0" Duration="0:0:0.2"/>
        </Storyboard>

If you’re starting to think this is getting repetitive then there’s a reason (that you’re thinking that – it is).

Now, let’s hook that in, first, just handle the Completed event of the spin:

         <Storyboard x :Key="sbSpin">
            <DoubleAnimation
              Storyboard.TargetName="SpinAndDisappear2"
              Storyboard.TargetProperty="(Button.RenderTransform).(RotateTransform.Angle)"
              From="0"
              To="360"
              Duration="0:0:3" Completed ="DoubleAnimation_Completed" />
        </Storyboard>

Finally, here’s the code for the DoubleAnimation_Completed:

         private void DoubleAnimation_Completed( object sender, EventArgs e)
        {
            Button b = ( Button)SpinAndDisappear;

            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);

        }

Again, not rocket science, but probably the least familiar thing so far. Basically, I’m taking a reference to the button, creating a DoubleAnimation and starting it (twice, one for width and one for height).

But that looks a bit odd… and seems useless

That’s it; you now have a button that spins, and then disappears. Okay, well, wouldn’t it be much better if it just span and disappeared at the same time?

Yes!

Next post!

Animation in XAML (Part 2)

Introduction

This is the second of my series of posts on animation, using WPF and XAML. In this post, I’m looking at how we can control an animation in WPF using code behind, and also, how two animations can be triggered simultaneously.

Button Animation in WPF with code-behind

The problem with a statement like this, is that you can pretty much replicate anything in XAML in code, so you can do everything in code, some, a little or nothing. So far, I’ve come across three approaches that make sense to me. In this article I’ll cover triggering animations from code behind; following articles will cover creating animations for elements that have the transform set in XAML, and finally, no XAML at all!

Triggering an animation from code

There’s little point in re-explaining the XAML; it’s essentially the same XAML that I’ve shown in the first post. It looks like this:


    <Window.Resources>
        <Storyboard x :Key="sbExpand">
            <DoubleAnimation
                Storyboard.TargetName="codebehindbutton"
                Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleX)"
                From="0" To ="1.2" Duration="0:0:0.3"/>
            <DoubleAnimation
                Storyboard.TargetName="codebehindbutton"
                Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleY)"
                From="0" To ="1.2" Duration="0:0:0.3"/>
       
            <DoubleAnimation
                Storyboard.TargetName="codebehindbutton"
                Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleX)"
                From="1.2" To ="1" Duration="0:0:0.3"
                BeginTime="0:0:0.3"/>
            <DoubleAnimation
                Storyboard.TargetName="codebehindbutton"
                Storyboard.TargetProperty="(Button.RenderTransform).(ScaleTransform.ScaleY)"
                From="1.2" To ="1" Duration="0:0:0.3"
                BeginTime="0:0:0.3"/>
        </Storyboard>
  

So, there’s a few things to note here:
– The storyboard is not part of the button definition; it’s actually part of the Window.Resources.
– We don’t use a named transition, but instead, specify the button name; however, we still have to tell the button that it has a transition:


    <Button Name ="codebehindbutton" Width="200" Height="150" Click="Button_Click" BorderThickness="2" Content="Don't Click Me">
          <Button.RenderTransform>
              <ScaleTransform 
                         ScaleX="1" ScaleY ="1" CenterX="100" CenterY="175"  />
          </Button.RenderTransform>
    </Button>

Generally speaking, there’s nothing new. The same transformation, the same effect; the only difference is that it’s defined as a resource for the Window rather than for the Button.

So, now we get to the crux; now that it doesn’t fire on a button event, how does it get fired? As usual with these things, it’s surprisingly easy when you look at the code:

    Storyboard sb = (Storyboard )FindResource("sbExpand");
    sb.Begin( this);

You also have access to the storyboard itself; for example, try this:

    Storyboard sb = (Storyboard )FindResource( "sbExpand");
    sb.AutoReverse = true;
    sb.Begin( this);

Multiple Animations

Cool eh?

Additionally, if you had two animations to start at the same time; this would be the way. For example, add the following label to your page:

         <Label x :Name="lblHello" Content="Spin Me!" Margin ="50,152,417,250" Width="50" Height="30"
               RenderTransformOrigin="0.5,0.5">
            <Label.RenderTransform>
                <RotateTransform/>
            </Label.RenderTransform>
        </Label>

And the following storyboard definition:

         <Storyboard x :Key="sbdLabelRotation">
            <DoubleAnimation
              Storyboard.TargetName="lblHello"
              Storyboard.TargetProperty="(Label.RenderTransform).(RotateTransform.Angle)"
              From="0"
              To="360"
              Duration="0:0:3"
              RepeatBehavior="4x" />
        </Storyboard>

(This was taken from the Laurent Bugnion article on the same subject http://www.galasoft.ch/mydotnet/articles/article-2006102701.aspx).

Now, try running both animations together:

             Storyboard sb = (Storyboard )FindResource("sbExpand");           
            sb.Begin( this);

             Storyboard sbdLabelRotation = (Storyboard)FindResource("sbdLabelRotation" );
            sbdLabelRotation.Begin( this);

Conclusion

So, both animations run at the same time. Admittedly, I’m not strictly sure what you could do with this particular animation; it’s certainly not my intention that WPF apps start taking a mid ’90s web-site feel!

In this article, we looked at controlling pre-defined storyboard definitions in code. In a future article, I intend to cover the creation of an animation from within code.