Infosys Microsoft Alliance and Solutions blog

« Adding Event handlers for controls in WPF (XAML) applications | Main | How many Threads have I got? »

WPF - Animate with less code

I have been playing around with Animation features of WPF and it has indeed made life easy for developers to build some cool animations quickly. Even if you don't go the extent of using Expression Studio to build complex animations, basic things can be easily done with WPF, XAML and code behind itself.

Whatever animation logic we write in XAML, we can write in code behind also. Though in code behind, this takes lot more lines of code and isn't that easily readable and understandable as it is XAML. In one of the samples that I was building, I had a requirement to animate a control, based on some existing data values.

This meant that I could not do a simple Event trigger implementation in XAML to get the animation going and had to work in the code behind. Without getting into too many complexities of my application, let me give a simple scenario here of animating width and height of a button control. To do this in code behind, the code will look something like this

        private void AnimatorClick(object sender, RoutedEventArgs e)
            DoubleAnimation db = new DoubleAnimation();
            db.From = 100;
            db.To = 300;
            db.AutoReverse = true;
            db.RepeatBehavior = RepeatBehavior.Forever;
            db.Duration = new Duration(TimeSpan.FromSeconds(2));

            DoubleAnimation db1 = new DoubleAnimation();
            db1.From = 50;
            db1.To = 150;
            db1.RepeatBehavior = RepeatBehavior.Forever;
            db1.AutoReverse = true;
            db1.Duration = db.Duration;
            Storyboard story = new Storyboard();

            Storyboard.SetTargetName(db, btn.Name);
            Storyboard.SetTargetProperty(db, new PropertyPath(Button.WidthProperty));

            Storyboard.SetTargetName(db1, btn.Name);
            Storyboard.SetTargetProperty(db1, new PropertyPath(Button.HeightProperty));

I can elimate the .From settings since I want to animate from existing size. This code has taken quite a few lines and animation logic is not even close to being complex. If I start to play around with more complex animation logic like say with Key frame animation, the lines of code will quickly shoot up. Fortunately, ability to call XAML resources in code behind can help with this issue.

Lets add the StoryBoard as a resource to the XAML file. This will be something as below

    <Storyboard x:Key="TestAnimation">
        <DoubleAnimation To="500" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" Storyboard.TargetName="btn" Storyboard.TargetProperty="Width"/>
        <DoubleAnimation To="350" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" Storyboard.TargetName="btn" Storyboard.TargetProperty="Height"/>

Now we will use the TryFindResource API to pick the resource from XAML and use in the code behind. We can use the FindResource API as well, but it will throw an exception if the resource isn't found and dealing with exceptions becomes performance draining. .NET has introduced a few similar Try type of APIs (TryGetValue, TryGetArrayLength etc, check documentation for complete listing) and these return a valid value or a null if not found. This is more performant then the earlier APIs when it comes to error conditions. Anyway, that is a separate topic. So back to the code behind file. The modified method will look like the following

        private void AnimatorClick(object sender, RoutedEventArgs e)
            Storyboard board = (Storyboard)TryFindResource("TestAnimation");
            if (board != null)

Not only does this help reduce the code clutter in the code behind file, this will also allow designers and developers to work in parallel. It is the designer who can plan the required animation and put that in XAML and all the developer needs to bother about is its name to invoke in the code behind. The same holds true for any other resource that you want to include in the XAML and use the code behind.

BTW, I can do with even less code as below, but note that it doesn't allows for error handling and assumes that the resource will be present. This can become troubling during development when the animation logic may not yet have been added to the XAML and hence during execution it will fail. I will recommend using the TryFindResource method.



How would one attach a storyboard to a control created at run-time?

The FindName does not return a find!

I found the answer.

One must use the 'RegisterName' function when making the control to be able to later find the control for 'SetTargetName'.

Richard, thanks for sharing your findings.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter