1
votes

I am working on a Windows 10 universal application targeting PC. I want to run an animation repeatedly (not in a "RepeatBehaviour" loop, but run it again after something else happens), but I am struggling with resetting the animated control AFTER animation completes.

One of the animations in a storyboard is TranslateTransform. After it completes, I can re-position the control using Canvas.SetLeft and Canvas.SetTop in code. However, after I "disappear" a control using ScaleTransform animation the control remains invisible and I cannot make it visible again. Changing control Height and Width does nothing.

Using AutoReverse in XAML does resolve the issue, but I do not want this to be visible to the user. The control is supposed to "disappear". I want to reset the control in code before the next run, behind the scenes.

My Storyboard and the Border control which I am animating are shown below. This works fine the first time. The image flies across the screen with some rotation and then disappears. Second time the image is invisible until the scale transform runs again.

I tried adding another ScaleTransform animation before the first key frame, to scale from 0 to 1 quickly (I tried duration of "0" or "0.1") but that breaks the whole thing for some reason.

I wonder if RenderTransformOrigin has something to do with this, but am unsure how to use it with TransformGroup. So it is set to (0.5,0.5) to center the rotation.

Any help would be appreciated.

 <Storyboard x:Name="myStoryboard">
        <DoubleAnimationUsingKeyFrames
                        Storyboard.TargetName="myImage"
                        Storyboard.TargetProperty="(Canvas.Top)"
                        EnableDependentAnimation="False">
                        <SplineDoubleKeyFrame x:Name="MyTopSpline"   KeyTime="0:0:1.9"/>
                    </DoubleAnimationUsingKeyFrames>

                    <DoubleAnimationUsingKeyFrames
                        Storyboard.TargetName="myImage"
                        Storyboard.TargetProperty="(Canvas.Left)"
                        EnableDependentAnimation="False"">
                        <SplineDoubleKeyFrame x:Name="MyLeftSpline" KeyTime="0:0:1.9"/>
                    </DoubleAnimationUsingKeyFrames>

                    <DoubleAnimation Storyboard.TargetName="myImage" 
                             Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" 
                             From="0" To="360" BeginTime="0:0:1.0" Duration="0:0:1.9" />

                    <DoubleAnimation Storyboard.TargetName="myImage"
                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)" 
                             From="1" To="0" BeginTime="0:0:1.9" Duration="0:0:0.9" />
                    <DoubleAnimation Storyboard.TargetName="myImage"
                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)" 
                             From="1" To="0" BeginTime="0:0:1.9" Duration="0:0:0.9"  />


</Storyboard>

  <Border Name="myImage"  Height="244" Width="244" Canvas.Left="200" Canvas.Top="100" Visibility="Collapsed" 
RenderTransformOrigin=".5,.5">
        <Border.RenderTransform>
            <TransformGroup>
                    <RotateTransform Angle="0" />
                    <ScaleTransform ScaleX="1" ScaleY="1" />
                </TransformGroup>
         </Border.RenderTransform>
</Border>
2

2 Answers

2
votes

First, let's clean up your code a bit. Instead of using a TransformGroup, you should use a composite transform object called CompositeTransform as it's a lot easier to work with. Don't forget to name it too.

<Border.RenderTransform>
    <CompositeTransform x:Name="myImageTransform" />
</Border.RenderTransform>

So now your Storyboard should look like the following. Note that I have added a myStoryboard_Completed handler to it.

<Storyboard x:Name="myStoryboard"
            Completed="myStoryboard_Completed">
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="myImage"
                                   Storyboard.TargetProperty="(Canvas.Top)">
        <SplineDoubleKeyFrame x:Name="MyTopSpline" KeyTime="0:0:1.9" />
    </DoubleAnimationUsingKeyFrames>

    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="myImage"
                                   Storyboard.TargetProperty="(Canvas.Left)">
        <SplineDoubleKeyFrame x:Name="MyLeftSpline" KeyTime="0:0:1.9" />
    </DoubleAnimationUsingKeyFrames>

    <DoubleAnimation Storyboard.TargetName="myImage"
                     Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)"
                     From="0"
                     To="360"
                     BeginTime="0:0:1.0"
                     Duration="0:0:1.9" />

    <DoubleAnimation Storyboard.TargetName="myImage"
                     Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
                     From="1"
                     To="0"
                     BeginTime="0:0:1.9"
                     Duration="0:0:0.9" />
    <DoubleAnimation Storyboard.TargetName="myImage"
                     Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)"
                     From="1"
                     To="0"
                     BeginTime="0:0:1.9"
                     Duration="0:0:0.9" />
</Storyboard>

Inside this handler, all you need to do is to reset all the transform attributes and canvas offsets.

private void myStoryboard_Completed(object sender, object e)
{
    myImage.Visibility = Visibility.Collapsed;

    Canvas.SetTop(myImage, 100);
    Canvas.SetLeft(myImage, 200);

    myImageTransform.Rotation = 0;
    myImageTransform.ScaleX = myImageTransform.ScaleY = 1;
}

But here is a better way.

Instead of doing some of the stuff in code behind, why not wrap all the logic inside the same Storyboard? All you need is to use DoubleAnimationUsingKeyFrames to define both start and end values for each of your animations.

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="myImage"
                                   Storyboard.TargetProperty="(Canvas.Top)">
        <SplineDoubleKeyFrame KeyTime="0:0:0" Value="100" />
        <SplineDoubleKeyFrame x:Name="MyTopSpline" KeyTime="0:0:1.9" Value="100" />
    </DoubleAnimationUsingKeyFrames>

    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="myImage"
                                   Storyboard.TargetProperty="(Canvas.Left)">
        <SplineDoubleKeyFrame KeyTime="0:0:0" Value="200" />
        <SplineDoubleKeyFrame x:Name="MyLeftSpline" KeyTime="0:0:1.9" Value="200" />
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)"
                                   Storyboard.TargetName="myImage">
        <EasingDoubleKeyFrame KeyTime="0" Value="0" />
        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
        <EasingDoubleKeyFrame KeyTime="0:0:2.9" Value="360" />
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
                                   Storyboard.TargetName="myImage">
        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:1.9" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:2.8" Value="0" />
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)"
                                   Storyboard.TargetName="myImage">
        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:1.9" Value="1" />
        <EasingDoubleKeyFrame KeyTime="0:0:2.8" Value="0" />
    </DoubleAnimationUsingKeyFrames>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                   Storyboard.TargetName="myImage">
        <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
        <DiscreteObjectKeyFrame KeyTime="0:0:3">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Collapsed</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
</Storyboard>

Hope this helps!

1
votes

Adding this line of code to StoryBoard completed event resolved the issue:

MyStoryboard.Stop();