简体   繁体   中英

Why does my Storyboard only run once?

I have a storyboard that I would like to run multiple times. Unfortunately, after it runs the first time, even when this code is hit, it doesn't animate again. It only animates the first time. I'm setting an initial value....even when I set the value before I run it again.

DoubleAnimationUsingKeyFrames animateTransformX = new DoubleAnimationUsingKeyFrames();

EasingDoubleKeyFrame initialTransformXKeyframe = new EasingDoubleKeyFrame();
initialTransformXKeyframe.KeyTime = TimeSpan.FromSeconds(0);
//Resetting the value before running it again.
initialTransformXKeyframe.Value = 0;
animateTransformX.KeyFrames.Add(initialTransformXKeyframe);


EasingDoubleKeyFrame animateTransformXKeyframe = new EasingDoubleKeyFrame();
animateTransformXKeyframe.KeyTime = TimeSpan.FromSeconds(0.5);
animateTransformXKeyframe.Value = aDynamicValueGoesHere; 
animateTransformX.KeyFrames.Add(animateTransformXKeyframe);


Storyboard.SetTarget(animateTransformX, image);
Storyboard.SetTargetProperty(animateTransformX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"));

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(animateTransformX);

myStoryboard.Begin(this);

I feel like it is very simple but for the life of me I can't understand why. Any help would be appreciated.

EDIT

The reason I was doing it from codebehind is because storyboards are freezable and I have had trouble in the past with dynamic values in them. For simplicity I didn't put that I was using a dynamic value in the code; I updated the code above to show I'm using a dynamic value.

I tried adding the storyboard as XAML inside a resource with the use of a dynamic value. It works fine (and replays) if a non-dynamic value is used but it only plays once (the first time) when a dynamic value is used.

So, if {Binding OffsetX} were replaced with 50 , for example, this works fine, and repeatedly. OffsetX gets updated through a property that implements INotifyPropertyChanged . Even if it were the same, if it were never updated, I would think it should still animate , just to the same value it animated to before (like it does with 50 ). But that isn't the case; it just doesn't animate again. So now I'm really lost.

<Storyboard x:Key="InitialAnimate">
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)" Storyboard.TargetName="StoryImage">
        <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="{Binding OffsetX}"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

EDIT 2

I didn't fix the problem but I found a workaround that works for my particular situation. I was getting this error in my output window:

System.Windows.Media.Animation Warning: 6 : Unable to perform action because the specified Storyboard was never applied to this object for interactive control.; Action='Stop'; Storyboard='System.Windows.Media.Animation.Storyboard'; Storyboard.HashCode='28715394'; Storyboard.Type='System.Windows.Media.Animation.Storyboard'; TargetElement='System.Windows.Controls.Grid'; TargetElement.HashCode='6255521'; TargetElement.Type='System.Windows.Controls.Grid'

I found a few StackOverflow answers regarding it, including how to find what Storyboard caused the issue and another unanswered question .

I am still not sure how to fix my original issue, but here's my workaround. Since I only needed the animation to run when you restarted (an event that happens in my viewmodel), I use an event raised in the viewmodel and consumed in the parent view to remove and then re-add the UserControl that contains the animation.

In that UserControl , I trigger the storyboard through a ControlStoryboardAction tied to a Loaded EventTrigger . This makes the animation run when it loads, and it only ever runs the animation once during the life of the UserControl . I am able to use the dynamic values in XAML. Here's how I'm removing and readding the view from it's parent:

Parent View:

<grid x:Name="imageHolder></grid>

Parent Codebehind:

private void CreateAnimations(object sender, EventArgs e)
{
    imageHolder.Children.RemoveAt(0);
    Views.Image image = new Image();
    image.Name = "image";
    imageHolder.Children.Add(image);
}

You can't change the Value property at runtime the way you're doing after the edit.

This is because Animations are freezable objects. There is more information in the MSDN Documentation, but basically it means you can't use binding because properties in the frozen object (ie the animation) cannot change.

To get around this limitation, you will need to do some or all of the work in code-behind.

See Why Storyboard value wouldn't get from a resource or binding?

So You probably want to go back to the codebehind method.

So as a final answer, what I would do is when I want to run it again:

  1. Remove the previous storyboard
  2. create a whole brand new Storyboard(or just the animation) and run that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM