Wpf: How to stop storyboard animation? - wpf

I have an Image and I'm trying to give the user the ability to change the animation of the image from several options. The user can select a new animation but sometimes the previous selected animation won't stop and I have 2 or more storyboards running at the same time on the Image.
I have this code:
private void animateZoom1(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[0] as DoubleAnimation);
}
private void animateZoom(Boolean mode)
{
if (mode)
{
effectSample.RenderTransform = new ScaleTransform();
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[0] as DoubleAnimation);
}
else
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
cancelAnimation("LogoStoryboard_Zoom");
}
}
private void animateZoom2(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, (FindResource("LogoStoryboard_Zoom") as Storyboard).Children[1] as DoubleAnimation);
}
private void animateOpacity(Boolean mode)
{
if (mode)
{
(FindResource("LogoStoryboard_Opacity") as Storyboard).Begin(this, true);
}
else
{
cancelAnimation("LogoStoryboard_Opacity");
}
}
private void animateScaleX2(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[1] as DoubleAnimation);
}
private void animateScaleX(object sender, EventArgs e)
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[0] as DoubleAnimation);
}
private void animateScaleX(Boolean mode)
{
if (mode)
{
effectSample.RenderTransform = new ScaleTransform();
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, (FindResource("LogoStoryboard_ScaleX") as Storyboard).Children[0] as DoubleAnimation);
}
else
{
effectSample.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
cancelAnimation("LogoStoryboard_ScaleX");
}
}
private void cancelAnimation(String storyBoardName)
{
(FindResource(storyBoardName) as Storyboard).Stop(this);
(FindResource(storyBoardName) as Storyboard).Remove(this);
}
and this
<Storyboard x:Key="LogoStoryboard_Zoom" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleY)"
By="0.5"
Duration="0:0:0.5"
BeginTime="0:0:0"
Completed="animateZoom2" />
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleY)"
By="-0.5"
Duration="0:0:0.5"
BeginTime="0:0:0"
Completed="animateZoom1" />
</Storyboard>
<Storyboard x:Key="LogoStoryboard_Opacity" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="0:0:8"
BeginTime="0:0:1"/>
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:8"
BeginTime="0:0:10"/>
</Storyboard>
<Storyboard x:Key="LogoStoryboard_ScaleX" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleX)"
To="0.5"
Duration="0:0:3"
BeginTime="0:0:0"
Completed="animateScaleX2"/>
<DoubleAnimation
Storyboard.TargetName="effectSample"
Storyboard.TargetProperty="(Image.RenderTransform).(ScaleTransform.ScaleX)"
To="1.5"
Duration="0:0:3"
BeginTime="0:0:0"
Completed="animateScaleX"/>
</Storyboard>
Please help me stop the old storyboard :)

Related

Animating two UserControls on the same ContentControl at the same time

I've these Load and Unload animations in App.xaml:
<Storyboard x:Key="Unload">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="-800"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Load">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<EasingDoubleKeyFrame KeyTime="0" Value="800"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
In my code I'm calling those on Button Clicks like these:
sb1 = FindResource("Unload") as Storyboard;
sb2 = FindResource("Load") as Storyboard;
void Button_Click(object sender, RoutedEventArgs e)
{
uc1.RenderTransform = GetTG();
uc2.RenderTransform = GetTG();
sb1.Begin(uc2);
sb2.Begin(uc1);
content.Content = uc1;
}
//and
void Button_Click_1(object sender, RoutedEventArgs e)
{
uc2.RenderTransform = GetTG();
uc1.RenderTransform = GetTG();
sb2.Begin(uc2);
sb1.Begin(uc1);
content.Content = uc2;
}
GetTG returns a TransformGroup
TransformGroup GetTG()
{
var tg = new TransformGroup();
tg.Children.Add(new ScaleTransform());
tg.Children.Add(new SkewTransform());
tg.Children.Add(new RotateTransform());
tg.Children.Add(new TranslateTransform());
return tg;
}
with these only the Load animation works. How to make both work at the same time?
Apply the animation to the ContentControl. This should slide out the current Content/UserControl to the left and slide in the new Content/UserControl from the right:
void Button_Click(object sender, RoutedEventArgs e)
{
UnLoadAndLoad(uc1);
}
void Button_Click_1(object sender, RoutedEventArgs e)
{
UnLoadAndLoad(uc2);
}
void UnLoadAndLoad(object ucToBeLoaded)
{
if (content.Content != ucToBeLoaded)
{
content.RenderTransform = GetTG();
EventHandler completed = null;
completed = (ss, ee) =>
{
sb1.Completed -= completed;
content.Content = ucToBeLoaded;
//load
sb2.Begin(content);
};
sb1.Completed += completed;
//unload
if (content.Content != null)
sb1.Begin(content);
else
completed(this, EventArgs.Empty);
}
}

how to do a pause before doing storyboard animation

I have this storyboard that starts when you hover over a grid:
<Storyboard x:Key="SB_MouseEnter">
<DoubleAnimation To="0" Storyboard.TargetName="gridNav"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TranslateTransform.Y)"
Duration="0:0:0.2"/>
</Storyboard>
I would like to hover over it for 500ms before it does its animation. How to accomplish this?
Specify BeginTime on your storyboard at which you want timeline to begin (0.5 secs in your case):
<DoubleAnimation To="0" Storyboard.TargetName="gridNav"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TranslateTransform.Y)"
Duration="0:0:0.2"
BeginTime="0:0:0.5"/>
You could use the DispatcherTimer class to wait for 500ms in combination with the UIElement.MouseEnter and UIElement.MouseLeave events, before manually starting the Storyboard with the Begin method. Try something like this:
private DispatcherTimer timer;
private void OnMouseEnterHandler(object sender, MouseEventArgs e)
{
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
timer.Tick += Timer_Tick;
timer.Start();
}
private void OnMouseLeaveHandler(object sender, MouseEventArgs e)
{
timer.Stop();
}
private void Timer_Tick(object sender, EventArgs e)
{
SB_MouseEnter.Begin();
timer.Stop();
}

VisualStateManager can't generate transitions for ThicknessAnimations

I have the following Visual States defined:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="EditStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:2"/>
</VisualStateGroup.Transitions>
<VisualState Name="Editing" />
<VisualState Name="Normal">
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="ViewBorder" Storyboard.TargetProperty="Margin" To="0" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="Header" Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)" To="0" Duration="0"/>
<ColorAnimation Storyboard.TargetName="EditBorder" Storyboard.TargetProperty="Background.Color" To="Red" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
The DoubleAnimation and ColorAnimation work fine, with VisualStateManager generating transition animations over 2 seconds for them.
However, the ThicknessAnimation does not animate. Instead it snaps to the finish value at the end of the transition period.
Is there any way to get VisualStateManager to generate transitions for it, or am I going to be forced to supply manual transitions?
I analyzed the problem and fired up .NET Reflector and found that the VisualStateManager only supports the following animations:
ColorAnimation
DoubleAnimation
PointAnimation
It's kind of crappy, because it's not documented anywhere.
To prove that it cannot generate the animations take a look at the reversed code of the VisualStageManager.GenerateToAnimation method. There is also a VisualStageManager.GenerateFromAnimation that supports the same subset of animations.
private static Timeline GenerateToAnimation(FrameworkElement root, Timeline timeline, IEasingFunction easingFunction, bool isEntering)
{
Timeline destination = null;
if (destination == null)
{
var targetColor = GetTargetColor(timeline, isEntering);
if (targetColor.HasValue)
destination = new ColorAnimation { To = targetColor, EasingFunction = easingFunction };
}
if (destination == null)
{
var targetDouble = GetTargetDouble(timeline, isEntering);
if (targetDouble.HasValue)
destination = new DoubleAnimation { To = targetDouble, EasingFunction = easingFunction };
}
if (destination == null)
{
var targetPoint = GetTargetPoint(timeline, isEntering);
if (targetPoint.HasValue)
destination = new PointAnimation { To = targetPoint, EasingFunction = easingFunction };
}
if (destination != null)
CopyStoryboardTargetProperties(root, timeline, destination);
return destination;
}
Bottomline... You can only use Color, Double or Point animations in the VisualStageManager. Revert to old-fashioned triggers if you need something else...
Maybe your ThicknessAnimation statement is not complete, i search the flowing code sample from MSDN in the topic "ThicknessAnimation Class".
<ThicknessAnimation
Storyboard.TargetProperty="BorderThickness"
Duration="0:0:1.5" FillBehavior="HoldEnd" From="1,1,1,1" To="28,14,28,14" />
Hope this could help you...

DoubleAnimation - On start event?

I have a storyboard defined:
<Grid.Resources>
<Storyboard x:Key="MasterAnim" x:Name="MasterAnim" Duration="0:0:10" >
<DoubleAnimation x:Name="ANIMATABLE_WidthExp"
Storyboard.TargetName="ANIMELEMENT_SboardRect1"
Storyboard.TargetProperty="Width"
From="100"
To="800"
Duration="0:0:5" />
<DoubleAnimation x:Name="ANIMATABLE_HeightExp"
Storyboard.TargetName="ANIMELEMENT_SboardRect1"
Storyboard.TargetProperty="Height"
From="100"
To="800"
BeginTime="0:0:5"
Duration="0:0:5" />
</Storyboard>
</Grid.Resources>
Is there any way of capturing when each of the double animations are about to start? I need to call a method on the element that it's targeting before the animation starts but im not sure what the best way to go about it is.
There's no Started event, but you can handle the CurrentTimeInvalidated, CurrentStateInvalidated and Completed events on the DoubleAnimation. CurrentStateInvalidated is probably all you need.
private void DoubleAnimationCurrentTimeInvalidated(object sender, EventArgs e)
{
var clock = (AnimationClock) sender;
Debug.WriteLine(string.Format("CurrentTime: state={0}, progress={1}, time={2}", clock.CurrentState, clock.CurrentProgress, clock.CurrentTime));
}
private void DoubleAnimationCurrentStateInvalidated(object sender, EventArgs e)
{
var clock = (AnimationClock)sender;
Debug.WriteLine(string.Format("CurrentState: state={0}", clock.CurrentState));
}
private void DoubleAnimationCompleted(object sender, EventArgs e)
{
var clock = (AnimationClock) sender;
Debug.WriteLine(string.Format("Completed: state={0}", clock.CurrentState));
}
Ignoring the current time we get
CurrentState: state=Active
CurrentState: state=Filling
Completed: state=Filling
when the animation runs.

How to do a code behind for Silverlight Storyboard Begintime instead of xaml

I need to translate this xaml code into code behind for begintime.
<Storyboard BeginTime="0:0:10" x:Name="sbEllipse1">
<DoubleAnimation
Storyboard.TargetName="myBrush1"
Storyboard.TargetProperty="RadiusX"
From="0" To="1"
Duration="0:0:20"
/>
<DoubleAnimation
Storyboard.TargetName="myBrush1"
Storyboard.TargetProperty="RadiusY"
From="0" To="1"
Duration="0:0:20"
/>
</Storyboard>
Storyboard sb = new Storyboard();
sb.BeginTime = TimeSpan.FromSeconds(10);
sb.Children.Add(new DoubleAnimation());
sb.Children.Add(new DoubleAnimation());
Storyboard sb = new Storyboard();
sb.BeginTime = TimeSpan.FromSeconds(10);
<DoubleAnimation
Storyboard.TargetName="myBrush1"
Storyboard.TargetProperty="RadiusX"
From="0" To="1"
Duration="0:0:20"
/>
//Equivalent code for the above is :
DoubleAnimation db = new DoubleAnimation();
db.From = 0;
db.To = 1;
db.Duration = new Duration(TimeSpan.FromSeconds(20));
Storyboard.SetTarget(db, myBrush1);
Storyboard.SetTargetProperty(db, RadiusX);
<DoubleAnimation
Storyboard.TargetName="myBrush1"
Storyboard.TargetProperty="RadiusY"
From="0" To="1"
Duration="0:0:20"
/>
//Equivalent code for the above is :
DoubleAnimation db1 = new DoubleAnimation();
db1.From = 0;
db1.To = 1;
db1.Duration = new Duration(TimeSpan.FromSeconds(20));
Storyboard.SetTarget(db, myBrush1);
Storyboard.SetTargetProperty(db, RadiusY);
//assigning both double animation to main Storyboard
sb.Children.Add(db);
sb.Children.Add(db1);
myBrush1.Resources.Add(storyboard);
sb.Begin();

Resources