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);
}