Thursday 20 March 2008

XAML Animation Differences Between WPF and Silverlight 2

I was working recently on adding some basic animations to a WPF application, and assumed I would simply be able to utilise the same syntax that I would if I was doing the same animation in Silverlight. Wrong!

I started by adding a couple of Storyboards to a Grid.Resources section:

<Page x:Class="LearningGames.NumbersPage"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="NumbersPage" Height="260">
     <Grid>
         <Grid.Resources>
          <Storyboard x:Name="storyboardWrong">
             <DoubleAnimation x:Name="da1" Storyboard.TargetName="labelWrong" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" />
             <DoubleAnimation x:Name="da2" Storyboard.TargetName="labelWrong" Storyboard.TargetProperty="Opacity" From="1" To="0" BeginTime="0:0:1" Duration="0:0:0.5" />
         </Storyboard>
         <Storyboard x:Name="storyboardRight">
             <DoubleAnimation x:Name="da3" Storyboard.TargetName="labelRight" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" />
             <DoubleAnimation x:Name="da4" Storyboard.TargetName="labelRight" Storyboard.TargetProperty="Opacity" From="1" To="0" BeginTime="0:0:1" Duration="0:0:0.5" />
         </Storyboard>
         </Grid.Resources>

In Silverlight 2, this would be enough. You could simply call storyboardWrong.Begin() in the code behind. But in WPF, things are a bit more complicated:

  • You need to specify x:Key for each Storyboard
  • The XAML compiler doesn't auto-generate member variables for each Storyboard.
  • Storyboards must be found using TryFindResource:
    storyboardWrong = (Storyboard)TryFindResource("storyboardWrong");
  • TryFindResource will only work if the Storyboard is in the Page.Resources section of the XAML
  • When you get round to running the Storyboard, it will need a parameter to the begin method. You can pass the "this" pointer:
    storyboardWrong.Begin(this);

So rather counter-intuitively, Silverlight actually makes some things easier than its more fully featured desktop counterpart WPF. Or am I missing some easier way of doing animation in WPF?

2 comments:

Anonymous said...

I came upon your page while searching for tutorials on creating buttons with the glass look.

The TryFindResource method searches up the visual tree, not down. For example, let's say you had a button on the page named "Button1" that was a child of the Page. In the code-behind, if you called Button1.TryFindResource("storyboardWrong"), you will be able to find the Storyboard that was placed in the Button's ResourceDictionary or in any of its parent's ResourceDictionaries.

Other than this small fact, I don't think there is an easier way to do animations in WPF.

Anonymous said...

try assigning it an x:Name
(having xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml")
and rebuilding the project
seems to work for me