Tags: | Posted by Admin on 7/15/2008 4:09 AM | Comments (0)

I'm trying to reuse an animation that I create programmatically.  The why isn't important.  What is important is that the second time I try to run it with animation.Begin(), it bombs.  Well, with some properties it bombs.  With others, it works.  Transform properties cause the error, but standard properties like opacity and canvas location work when you run the animation multiple times.

Below is a sample app.  Button one and two are two instances of the same created animation.  Each of them will run once, but fail the second time.  This shows that it's not the object being animated, but the animation itself that is causing the error.  Button three and four are opacity animations, and show that animations that change opacity never fail when run multiple times.

I'm sure one suggestion will be to recreate the animation each time.  However, in my real-world app, I capture some object properties at the time the animation is created, and need to have these same values used each time the animation runs.  If I were to grab the properties over each time I recreated the animation, the object might be in a different state.  And I don't want to cache the initial values, because 1) it makes my animation library less flexible, and 2) I just want to do it this way, 'cause it's easier :).

I've added my code after the sample app.  If anyone has any idea what I can do to prevent this while still creating the animations programmatically, please add a comment.

 

Here is the xaml (Page.xaml).

<UserControl x:Class="AnimationReuseTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle x:Name="recMain" Height="54" Canvas.Top="225" Stroke="#FF000000" Margin="65,136,76,110" VerticalAlignment="Stretch" d:LayoutOverrides="Height" Fill="#FF941414" RenderTransformOrigin="0.5,0.5" Opacity="0.1" >
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
                    <SkewTransform/>
                    <RotateTransform/>
                    <TranslateTransform/>
                </TransformGroup>
            </Rectangle.RenderTransform>
        </Rectangle>
        <Button Height="40" Margin="24,0,0,70" VerticalAlignment="Bottom" Content="Animate1-scalex" x:Name="btnAnimate1" Click="btnAnimate1_Click" Width="163" HorizontalAlignment="Left"/>
        <Button Height="40" Margin="0,0,37,70" VerticalAlignment="Bottom" Content="Animate2-scalex" x:Name="btnAnimate2" Click="btnAnimate2_Click" Width="163" HorizontalAlignment="Right"/>
        <Button Margin="24,0,0,26" VerticalAlignment="Bottom" Content="Animate3-opacity" x:Name="btnAnimate3" Click="btnAnimate3_Click" HorizontalAlignment="Left" Width="163" Height="40"/>
        <Button Height="40" Margin="0,0,37,26" VerticalAlignment="Bottom" Content="Animate4-opacity" x:Name="btnAnimate4" Click="btnAnimate4_Click" Width="163" HorizontalAlignment="Right"/>
        <TextBlock Height="124" Margin="8,8,8,0" VerticalAlignment="Top" TextWrapping="Wrap" x:Name="lblErrorMsg" FontSize="8" />
    </Grid>
</UserControl>

And here is the code (Page.xaml.vb).

Partial Public Class Page
    Inherits UserControl

    Dim s1 As New Storyboard
    Dim s2 As New Storyboard
    Dim s3 As New Storyboard
    Dim s4 As New Storyboard

    Public Sub New()
        InitializeComponent()

        'add storyboards to resources - not sure why, but I'm following examples I've seen
        LayoutRoot.Resources.Add("S1", s1)
        LayoutRoot.Resources.Add("S2", s2)
        LayoutRoot.Resources.Add("S3", s3)
        LayoutRoot.Resources.Add("S4", s4)
        'initialize the storyboard to animate the rectangle
        CreateAnimation(s1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)")
        CreateAnimation(s2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)")
        CreateAnimation(s3, "(UIElement.Opacity)")
        CreateAnimation(s4, "(UIElement.Opacity)")
    End Sub

    Sub CreateAnimation(ByVal s As Storyboard, ByVal Prop As String)
        'create new doubleanimation
        Dim d As New DoubleAnimation
        'set timespan to half a second
        d.Duration = New Duration(TimeSpan.FromSeconds(0.5))
        'reverse animation
        d.AutoReverse = True
        'set target to the rectangle
        Storyboard.SetTarget(d, recMain)
        'we're animating x-axis scale - other props, like (Canvas.X) will work, though
        Storyboard.SetTargetProperty(d, New PropertyPath(Prop))
        'animating from start value of to 1
        d.To = 1
        'add doubleanimation to storyboard
        s.Children.Add(d)
    End Sub

    Private Sub btnAnimate1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'begin animation when button is clicked - we'll get the error below the second time we click the button.
        'Cannot resolve TargetProperty (UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX) on specified object.
        Try
            s1.Begin()
        Catch ex As Exception
            lblErrorMsg.text = ex.ToString
        End Try
    End Sub

    Private Sub btnAnimate2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'begin animation when button is clicked - we'll get the error below the second time we click the button.
        'Cannot resolve TargetProperty (UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX) on specified object.
        Try
            s2.Begin()
        Catch ex As Exception
            lblErrorMsg.text = ex.ToString
        End Try
    End Sub

    Private Sub btnAnimate3_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'begin animation when button is clicked - we won't get an error on animating
        s3.Begin()
    End Sub

    Private Sub btnAnimate4_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'begin animation when button is clicked - we won't get an error on animating
        s4.Begin()
    End Sub
End Class

Comments