Answered by:
How can I find out if a Storyboard is active?

Question
-
Hello,
I use a Storyboard for animations. I need to find out if a StoryBoarde is active, i.e. if Begin() was called and the animation hasn't finished yet.
I defined the storyboard in xaml. In code I have this:private void startAnimation_Click(object sender, RoutedEventArgs e) { Storyboard sb = this.Resources["myStoryboard"] as Storyboard; sb.Begin(this, true); } protected override void OnPreviewKeyDown(KeyEventArgs e) { Storyboard sb = this.Resources["myStoryboard"] as Storyboard; bool isActive = !(sb.GetCurrentState() == ClockState.Stopped); e.Handled = isActive; }
The problem: sb.GetCurrentState() throws an InvalidOperationException after the animation is started.
I use VS2008 SP1 and .NET 3.5 SP1.
Any help is appreciated.
- Edited by nruessmann Thursday, October 23, 2008 10:10 PM
Thursday, October 23, 2008 10:08 PM
Answers
-
this is a snapshot of a debug session. i modified the code you had in a related post(i put in a lot more than i probably should but it's just for my convenience).the modified code follows the debug snapshot. so the current states do change.The thread 0xd54 has exited with code 0 (0x0).
OnPreviewMouseLeftButtonDown secondClock state: Active, mainClock state: Active
OnPreviewMouseUp secondClock state: Active, mainClock state: Active
_showSecond_Click secondClock state: Active, mainClock state: Active
_showSecond_Click secondClock state: Active, mainClock state: Active
showSecond_Completed secondClock state: Filling, mainClock state: Filling
OnPreviewMouseLeftButtonDown secondClock state: Filling, mainClock state: Filling
OnPreviewMouseUp secondClock state: Filling, mainClock state: Filling
_showMain_Click secondClock state: Filling, mainClock state: Filling
showMain_Completed secondClock state: Filling, mainClock state: Filling
The thread 0x1400 has exited with code 0 (0x0).
--------------------------------
namespace MyWpfTests
{
/// <summary>
/// Interaction logic for StoryBoardActive.xaml
/// </summary>
public partial class StoryBoardActive : Window
{
private bool _isStoryBordActive = false;
ClockGroup showSecondClock;
ClockGroup showMainClock;
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewMouseLeftButtonDown secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewMouseLeftButtonDown(e);
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewKeyDown secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewKeyDown(e);
}
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewMouseUp secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewMouseUp(e);
}
private bool IsAnimationRunning
{
get
{
return _isStoryBordActive;
}
}
public StoryBoardActive()
{
InitializeComponent();
Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard;
showSecondClock = showSecond.CreateClock();
Storyboard showMain = this.Resources["_storyboardShowSecond"] as Storyboard;
showMainClock = showMain.CreateClock();
}
private void _showSecond_Click(object sender, RoutedEventArgs e)
{
_isStoryBordActive = true;
_secondGrid.Visibility = Visibility.Visible;
Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard;
Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
_isStoryBordActive = showSecond.CreateClock().CurrentState == ClockState.Active;
showSecond.Completed += new EventHandler(showSecond_Completed);
showSecond.Begin(this, true);
Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
}
void showSecond_Completed(object sender, EventArgs e)
{
_mainGrid.Visibility = Visibility.Collapsed;
_isStoryBordActive = false;
Debug.WriteLine(string.Format("showSecond_Completed secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
}
private void _showMain_Click(object sender, RoutedEventArgs e)
{
_isStoryBordActive = true;
_mainGrid.Visibility = Visibility.Visible;
Debug.WriteLine(string.Format("_showMain_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
Storyboard showMain = this.Resources["_storyboardHideSecond"] as Storyboard;
showMain.Completed += new EventHandler(showMain_Completed);
showMain.Begin(this, true);
}
void showMain_Completed(object sender, EventArgs e)
{
_secondGrid.Visibility = Visibility.Collapsed;
Debug.WriteLine(string.Format("showMain_Completed secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
_isStoryBordActive = false;
}
}
}
Hope this helps.
Evan Chua-Yap
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
Friday, October 24, 2008 1:17 PM -
Hi Norbert,(Post 1 of 2)What you are observing is similar to this MSDN Sample:http://msdn.microsoft.com/en-us/library/system.windows.media.animation.clock.currentstate.aspxPlease read that article because it gives more information there than I will mention/repeat here.That sample displays CurrentTime and CurrentState information for a parent StoryBoard and its children animations. If you run the sample, the results you'll get will be similar to the results shown below:
StoryBoard: 00:00:00:Active 00:00:00:Filling
Animation1: 00:00:01.0206088:Active 00:00:09.9898286:Active 00:00:00.9899568:Stopped 00:00:01.0100249:Active 00:00:09.9901032:Active 00:00:00.9902314:Stopped
Animation2: 00:00:01.0206088:Active 00:00:09.0204949:Filling 00:00:08.9898428:Active 00:00:00.9899568:Stopped 00:00:01.0100249:Active 00:00:09.0099111:Filling 00:00:08.9901174:Active 00:00:00.9902314:Stopped
So here you see that upon completion, the StoryBoard is reporting a CurrentState of Filling. I don't know why it's not reporting Stopped. Someone from Microsoft should know.
Animations with FillBehavior=HoldEnd and Stop will upon completion report its current state to be Filling and Stopped respectively also. I understand that FillBehavior=HoldEnd means the animated property will retain its last animated value, and FillBehavior=Stop means the animated property will revert back to its initial state. What i don't understand is why upon completion, both animations don't report their current state as Stopped. Again, this is something that Microsoft can explain better and why. If you run the sample code below, the results you'll get will be similar to:
Current Time: 00:00:00, Current State: Active
Current Time: 00:00:03, Current State: Filling
daHoldEnd_Completed current state: Filling
Current Time: 00:00:00, Current State: Active
Current Time: , Current State: Stopped
daStop_Completed current state: Stopped
AnimateRect.xaml
<Window x:Class="WpfAnimationProblem.AnimateRect"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnimateRect" Height="300" Width="300">
<Window.Resources>
<DoubleAnimation x:Key="daHoldEnd" From="1" To="2"
Duration="0:0:3" FillBehavior="HoldEnd" CurrentStateInvalidated="DoubleAnimation_CurrentStateInvalidated" />
<DoubleAnimation x:Key="daStop" From="1" To="2"
Duration="0:0:3" FillBehavior="Stop" CurrentStateInvalidated="DoubleAnimation_CurrentStateInvalidated" />
</Window.Resources>
<StackPanel>
<Rectangle x:Name="rect" Fill="Blue" Height="50" Width="100" Margin="10" HorizontalAlignment="Left">
<Rectangle.RenderTransform>
<ScaleTransform x:Name="rectScale"/>
</Rectangle.RenderTransform>
</Rectangle>
<Button x:Name="doDAHoldEnd" Content="doDAHoldEnd" Margin="10" Click="doDAHoldEnd_Click" HorizontalAlignment="Center"/>
<Button x:Name="doDAStop" Content="doDAStop" Margin="10" Click="doDAStop_Click" HorizontalAlignment="Center"/>
</StackPanel>
</Window>
AnimateRect.xaml.cs
namespace WpfAnimationProblem
{
/// <summary>
/// Interaction logic for AnimateRect.xaml
/// </summary>
public partial class AnimateRect : Window
{
DoubleAnimation da;
AnimationClock ac;
public AnimateRect()
{
InitializeComponent();
}
private void doDAHoldEnd_Click(object sender, RoutedEventArgs e)
{
da = Resources["daHoldEnd"] as DoubleAnimation;
ScaleTransform st = FindName("rectScale") as ScaleTransform;
ac = da.CreateClock();
ac.Completed += new EventHandler(daHoldEnd_Completed);
st.ApplyAnimationClock(ScaleTransform.ScaleXProperty, ac);
}
void daHoldEnd_Completed(object sender, EventArgs e)
{
AnimationClock ac1 = sender as AnimationClock;
Debug.WriteLine(string.Format("daHoldEnd_Completed current state: {0}", ac1.CurrentState));
}
private void doDAStop_Click(object sender, RoutedEventArgs e)
{
da = Resources["daStop"] as DoubleAnimation;
ScaleTransform st = FindName("rectScale") as ScaleTransform;
ac = da.CreateClock();
ac.Completed += new EventHandler(daStop_Completed);
st.ApplyAnimationClock(ScaleTransform.ScaleXProperty, ac);
}
void daStop_Completed(object sender, EventArgs e)
{
AnimationClock ac1 = sender as AnimationClock;
Debug.WriteLine(string.Format("daStop_Completed current state: {0}", ac1.CurrentState));
}
private void DoubleAnimation_CurrentStateInvalidated(object sender, EventArgs e)
{
AnimationClock clock = sender as AnimationClock;
Debug.WriteLine(string.Format("Current Time: {0}, Current State: {1}", clock.CurrentTime, clock.CurrentState));
}
}
}
Evan Chua-Yap
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
Saturday, October 25, 2008 2:08 PM
All replies
-
tryClockGroup sbClock = sb.CreateClock();then to test, access sbClock.CurrentStatehope this helpsevan chua-yapFriday, October 24, 2008 12:02 AM
-
I tried with sb.CreateClock()
No exception thrown, but not working either.
sbClock.CurrentState always return Stopped, independent of what the storyboard is doing or not.
Friday, October 24, 2008 9:32 AM -
this is a snapshot of a debug session. i modified the code you had in a related post(i put in a lot more than i probably should but it's just for my convenience).the modified code follows the debug snapshot. so the current states do change.The thread 0xd54 has exited with code 0 (0x0).
OnPreviewMouseLeftButtonDown secondClock state: Active, mainClock state: Active
OnPreviewMouseUp secondClock state: Active, mainClock state: Active
_showSecond_Click secondClock state: Active, mainClock state: Active
_showSecond_Click secondClock state: Active, mainClock state: Active
showSecond_Completed secondClock state: Filling, mainClock state: Filling
OnPreviewMouseLeftButtonDown secondClock state: Filling, mainClock state: Filling
OnPreviewMouseUp secondClock state: Filling, mainClock state: Filling
_showMain_Click secondClock state: Filling, mainClock state: Filling
showMain_Completed secondClock state: Filling, mainClock state: Filling
The thread 0x1400 has exited with code 0 (0x0).
--------------------------------
namespace MyWpfTests
{
/// <summary>
/// Interaction logic for StoryBoardActive.xaml
/// </summary>
public partial class StoryBoardActive : Window
{
private bool _isStoryBordActive = false;
ClockGroup showSecondClock;
ClockGroup showMainClock;
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewMouseLeftButtonDown secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewMouseLeftButtonDown(e);
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewKeyDown secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewKeyDown(e);
}
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
ClockState cs = showSecondClock.CurrentState;
ClockState cs2 = showMainClock.CurrentState;
Debug.WriteLine(string.Format("OnPreviewMouseUp secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
e.Handled = IsAnimationRunning;
base.OnPreviewMouseUp(e);
}
private bool IsAnimationRunning
{
get
{
return _isStoryBordActive;
}
}
public StoryBoardActive()
{
InitializeComponent();
Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard;
showSecondClock = showSecond.CreateClock();
Storyboard showMain = this.Resources["_storyboardShowSecond"] as Storyboard;
showMainClock = showMain.CreateClock();
}
private void _showSecond_Click(object sender, RoutedEventArgs e)
{
_isStoryBordActive = true;
_secondGrid.Visibility = Visibility.Visible;
Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard;
Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
_isStoryBordActive = showSecond.CreateClock().CurrentState == ClockState.Active;
showSecond.Completed += new EventHandler(showSecond_Completed);
showSecond.Begin(this, true);
Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
}
void showSecond_Completed(object sender, EventArgs e)
{
_mainGrid.Visibility = Visibility.Collapsed;
_isStoryBordActive = false;
Debug.WriteLine(string.Format("showSecond_Completed secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
}
private void _showMain_Click(object sender, RoutedEventArgs e)
{
_isStoryBordActive = true;
_mainGrid.Visibility = Visibility.Visible;
Debug.WriteLine(string.Format("_showMain_Click secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
Storyboard showMain = this.Resources["_storyboardHideSecond"] as Storyboard;
showMain.Completed += new EventHandler(showMain_Completed);
showMain.Begin(this, true);
}
void showMain_Completed(object sender, EventArgs e)
{
_secondGrid.Visibility = Visibility.Collapsed;
Debug.WriteLine(string.Format("showMain_Completed secondClock state: {0}, mainClock state: {1}",
showSecondClock.CurrentState, showMainClock.CurrentState));
_isStoryBordActive = false;
}
}
}
Hope this helps.
Evan Chua-Yap
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
Friday, October 24, 2008 1:17 PM -
Hello Evan,
thanks for the code. I used it exactly as you send it.
But it still does not solve the problem. When I start the programm and click somewhere in the window several times, I get the ACTIVE as state and then FILLING. More clicking (not on the buttons) gives FILLING.
After that I only get FILLING, before an animation is started, while an animation is running, and after an animation is completed.
I use VS2008 SP1 and .NET 3.5 SP1
Here is the code I used:
Window1.xaml.cs:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Media.Animation; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Interop; using System.Diagnostics; namespace WpfAnamationProblem { public partial class Window1 : Window { private bool _isStoryBordActive = false; ClockGroup showSecondClock; ClockGroup showMainClock; protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) { ClockState cs = showSecondClock.CurrentState; ClockState cs2 = showMainClock.CurrentState; Debug.WriteLine(string.Format("OnPreviewMouseLeftButtonDown secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); e.Handled = IsAnimationRunning; base.OnPreviewMouseLeftButtonDown(e); } protected override void OnPreviewKeyDown(KeyEventArgs e) { ClockState cs = showSecondClock.CurrentState; ClockState cs2 = showMainClock.CurrentState; Debug.WriteLine(string.Format("OnPreviewKeyDown secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); e.Handled = IsAnimationRunning; base.OnPreviewKeyDown(e); } protected override void OnPreviewMouseUp(MouseButtonEventArgs e) { ClockState cs = showSecondClock.CurrentState; ClockState cs2 = showMainClock.CurrentState; Debug.WriteLine(string.Format("OnPreviewMouseUp secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); e.Handled = IsAnimationRunning; base.OnPreviewMouseUp(e); } private bool IsAnimationRunning { get { return _isStoryBordActive; } } public Window1() { InitializeComponent(); Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard; showSecondshowSecondClock = showSecond.CreateClock(); Storyboard showMain = this.Resources["_storyboardShowSecond"] as Storyboard; showMainshowMainClock = showMain.CreateClock(); } private void _showSecond_Click(object sender, RoutedEventArgs e) { _isStoryBordActive = true; _secondGrid.Visibility = Visibility.Visible; Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard; Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); _isStoryBordActive = showSecond.CreateClock().CurrentState == ClockState.Active; showSecond.Completed += new EventHandler(showSecond_Completed); showSecond.Begin(this, true); Debug.WriteLine(string.Format("_showSecond_Click secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); } void showSecond_Completed(object sender, EventArgs e) { _mainGrid.Visibility = Visibility.Collapsed; _isStoryBordActive = false; Debug.WriteLine(string.Format("showSecond_Completed secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); } private void _showMain_Click(object sender, RoutedEventArgs e) { _isStoryBordActive = true; _mainGrid.Visibility = Visibility.Visible; Debug.WriteLine(string.Format("_showMain_Click secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); Storyboard showMain = this.Resources["_storyboardHideSecond"] as Storyboard; showMain.Completed += new EventHandler(showMain_Completed); showMain.Begin(this, true); } void showMain_Completed(object sender, EventArgs e) { _secondGrid.Visibility = Visibility.Collapsed; Debug.WriteLine(string.Format("showMain_Completed secondClock state: {0}, mainClock state: {1}", showSecondClock.CurrentState, showMainClock.CurrentState)); _isStoryBordActive = false; } } }
Window1.xaml:<Window x:Class="WpfAnamationProblem.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" ResizeMode = "NoResize" WindowStyle= "ThreeDBorderWindow" AllowDrop="false"> <Window.Resources> <Storyboard x:Key="_storyboardShowSecond" > <DoubleAnimation Storyboard.TargetName="_mainTransform" Storyboard.TargetProperty="ScaleX" From="1" To="0" Duration="0:0:3" FillBehavior="HoldEnd" /> <DoubleAnimation Storyboard.TargetName="_secondTransform" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:3" FillBehavior="HoldEnd" /> </Storyboard> <Storyboard x:Key="_storyboardHideSecond" > <DoubleAnimation Storyboard.TargetName="_mainTransform" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:3" FillBehavior="HoldEnd" /> <DoubleAnimation Storyboard.TargetName="_secondTransform" Storyboard.TargetProperty="ScaleX" From="1" To="0" Duration="0:0:3" FillBehavior="HoldEnd" /> </Storyboard> </Window.Resources> <StackPanel Orientation="Horizontal" Name="_main_"> <Grid Name="_mainGrid"> <Grid.LayoutTransform> <ScaleTransform x:Name="_mainTransform" ScaleX="1" /> </Grid.LayoutTransform> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Label Grid.Column="0" Grid.Row="0">Label 1 Main:</Label> <TextBox Grid.Column="1" Grid.Row="0" Text="TextBox 1 main" IsEnabled="False" /> <Label Grid.Column="0" Grid.Row="1">Label 2 Main:</Label> <TextBox Grid.Column="1" Grid.Row="1" Text="TextBox 2 main" /> <Button Name="_showSecond" Content="Show Second" Grid.Column="1" Grid.Row="3" Click="_showSecond_Click"/> </Grid> <Grid Name="_secondGrid" Visibility="Collapsed"> <Grid.LayoutTransform> <ScaleTransform x:Name="_secondTransform" ScaleX="0" /> </Grid.LayoutTransform> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Label Grid.Column="0" Grid.Row="0">Label 1 Second:</Label> <TextBox Grid.Column="1" Grid.Row="0" Text="TextBox 1 second" IsEnabled="False"/> <Label Grid.Column="0" Grid.Row="1">Label 2 Second:</Label> <TextBox Grid.Column="1" Grid.Row="1" Text="TextBox 2 second" /> <Button Name="_showMain" Content="Show Main" Grid.Column="1" Grid.Row="3" Click="_showMain_Click" /> </Grid> </StackPanel> </Window>
Friday, October 24, 2008 11:01 PM -
Hi Norbert,(Post 1 of 2)What you are observing is similar to this MSDN Sample:http://msdn.microsoft.com/en-us/library/system.windows.media.animation.clock.currentstate.aspxPlease read that article because it gives more information there than I will mention/repeat here.That sample displays CurrentTime and CurrentState information for a parent StoryBoard and its children animations. If you run the sample, the results you'll get will be similar to the results shown below:
StoryBoard: 00:00:00:Active 00:00:00:Filling
Animation1: 00:00:01.0206088:Active 00:00:09.9898286:Active 00:00:00.9899568:Stopped 00:00:01.0100249:Active 00:00:09.9901032:Active 00:00:00.9902314:Stopped
Animation2: 00:00:01.0206088:Active 00:00:09.0204949:Filling 00:00:08.9898428:Active 00:00:00.9899568:Stopped 00:00:01.0100249:Active 00:00:09.0099111:Filling 00:00:08.9901174:Active 00:00:00.9902314:Stopped
So here you see that upon completion, the StoryBoard is reporting a CurrentState of Filling. I don't know why it's not reporting Stopped. Someone from Microsoft should know.
Animations with FillBehavior=HoldEnd and Stop will upon completion report its current state to be Filling and Stopped respectively also. I understand that FillBehavior=HoldEnd means the animated property will retain its last animated value, and FillBehavior=Stop means the animated property will revert back to its initial state. What i don't understand is why upon completion, both animations don't report their current state as Stopped. Again, this is something that Microsoft can explain better and why. If you run the sample code below, the results you'll get will be similar to:
Current Time: 00:00:00, Current State: Active
Current Time: 00:00:03, Current State: Filling
daHoldEnd_Completed current state: Filling
Current Time: 00:00:00, Current State: Active
Current Time: , Current State: Stopped
daStop_Completed current state: Stopped
AnimateRect.xaml
<Window x:Class="WpfAnimationProblem.AnimateRect"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnimateRect" Height="300" Width="300">
<Window.Resources>
<DoubleAnimation x:Key="daHoldEnd" From="1" To="2"
Duration="0:0:3" FillBehavior="HoldEnd" CurrentStateInvalidated="DoubleAnimation_CurrentStateInvalidated" />
<DoubleAnimation x:Key="daStop" From="1" To="2"
Duration="0:0:3" FillBehavior="Stop" CurrentStateInvalidated="DoubleAnimation_CurrentStateInvalidated" />
</Window.Resources>
<StackPanel>
<Rectangle x:Name="rect" Fill="Blue" Height="50" Width="100" Margin="10" HorizontalAlignment="Left">
<Rectangle.RenderTransform>
<ScaleTransform x:Name="rectScale"/>
</Rectangle.RenderTransform>
</Rectangle>
<Button x:Name="doDAHoldEnd" Content="doDAHoldEnd" Margin="10" Click="doDAHoldEnd_Click" HorizontalAlignment="Center"/>
<Button x:Name="doDAStop" Content="doDAStop" Margin="10" Click="doDAStop_Click" HorizontalAlignment="Center"/>
</StackPanel>
</Window>
AnimateRect.xaml.cs
namespace WpfAnimationProblem
{
/// <summary>
/// Interaction logic for AnimateRect.xaml
/// </summary>
public partial class AnimateRect : Window
{
DoubleAnimation da;
AnimationClock ac;
public AnimateRect()
{
InitializeComponent();
}
private void doDAHoldEnd_Click(object sender, RoutedEventArgs e)
{
da = Resources["daHoldEnd"] as DoubleAnimation;
ScaleTransform st = FindName("rectScale") as ScaleTransform;
ac = da.CreateClock();
ac.Completed += new EventHandler(daHoldEnd_Completed);
st.ApplyAnimationClock(ScaleTransform.ScaleXProperty, ac);
}
void daHoldEnd_Completed(object sender, EventArgs e)
{
AnimationClock ac1 = sender as AnimationClock;
Debug.WriteLine(string.Format("daHoldEnd_Completed current state: {0}", ac1.CurrentState));
}
private void doDAStop_Click(object sender, RoutedEventArgs e)
{
da = Resources["daStop"] as DoubleAnimation;
ScaleTransform st = FindName("rectScale") as ScaleTransform;
ac = da.CreateClock();
ac.Completed += new EventHandler(daStop_Completed);
st.ApplyAnimationClock(ScaleTransform.ScaleXProperty, ac);
}
void daStop_Completed(object sender, EventArgs e)
{
AnimationClock ac1 = sender as AnimationClock;
Debug.WriteLine(string.Format("daStop_Completed current state: {0}", ac1.CurrentState));
}
private void DoubleAnimation_CurrentStateInvalidated(object sender, EventArgs e)
{
AnimationClock clock = sender as AnimationClock;
Debug.WriteLine(string.Format("Current Time: {0}, Current State: {1}", clock.CurrentTime, clock.CurrentState));
}
}
}
Evan Chua-Yap
- Marked as answer by Jim Zhou - MSFT Thursday, October 30, 2008 9:36 AM
Saturday, October 25, 2008 2:08 PM -
Post 2 of 2.I think the reason why you're not getting a Stopped current state has to do with your DA's FillBehavior=HoldEnd. (I know FillBehavior=HoldEnd is the correct setting for your scenario so I'm not saying you're doing anything wrong. Just need to understand from Microsoft why completed Animations don't always report a Stopped current state)I modified your code to do something similar to the MSDN sample. If you run the modified code, the results will be similar to:
StoryboardShowSecond_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecondMT_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecondST_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecond_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardShowSecondMT_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardShowSecondST_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardHideSecond_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardHideSecondMT_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardHideSecondST_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardHideSecond_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardHideSecondMT_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardHideSecondST_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardShowSecond_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecondMT_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecondST_CurrentStateInvalidated Time: 00:00:00, State: Active
StoryboardShowSecond_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardShowSecondMT_CurrentStateInvalidated Time: 00:00:03, State: Filling
StoryboardShowSecondST_CurrentStateInvalidated Time: 00:00:03, State: Filling
....
xaml
<Window x:Class="WpfAnimationProblem.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window4" Height="300" Width="300">
<Window.Resources>
<Storyboard x:Key="_storyboardShowSecond" CurrentStateInvalidated="StoryboardShowSecond_CurrentStateInvalidated">
<DoubleAnimation Storyboard.TargetName="_mainTransform" Storyboard.TargetProperty="ScaleX" From="1" To="0" Duration="0:0:3"
FillBehavior="HoldEnd" CurrentStateInvalidated="StoryboardShowSecondMT_CurrentStateInvalidated"/>
<DoubleAnimation Storyboard.TargetName="_secondTransform" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:3"
FillBehavior="HoldEnd" CurrentStateInvalidated="StoryboardShowSecondST_CurrentStateInvalidated"/>
</Storyboard>
<Storyboard x:Key="_storyboardHideSecond" CurrentStateInvalidated="StoryboardHideSecond_CurrentStateInvalidated">
<DoubleAnimation Storyboard.TargetName="_mainTransform" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:3"
FillBehavior="HoldEnd" CurrentStateInvalidated="StoryboardHideSecondMT_CurrentStateInvalidated" />
<DoubleAnimation Storyboard.TargetName="_secondTransform" Storyboard.TargetProperty="ScaleX" From="1" To="0" Duration="0:0:3"
FillBehavior="HoldEnd" CurrentStateInvalidated="StoryboardHideSecondST_CurrentStateInvalidated"/>
</Storyboard>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<Grid Name="_mainGrid">
<Grid.LayoutTransform>
<ScaleTransform x:Name="_mainTransform" ScaleX="1" />
</Grid.LayoutTransform>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0">Label 1 Main:</Label>
<TextBox Grid.Column="1" Grid.Row="0" Text="TextBox 1 main" />
<Label Grid.Column="0" Grid.Row="1">Label 2 Main:</Label>
<TextBox Grid.Column="1" Grid.Row="1" Text="TextBox 2 main" />
<Button Name="_showSecond" Content="Show Second" Grid.Column="1" Grid.Row="3" Click="_showSecond_Click"/>
</Grid>
<Grid Name="_secondGrid" Visibility="Collapsed">
<Grid.LayoutTransform>
<ScaleTransform x:Name="_secondTransform" ScaleX="0" />
</Grid.LayoutTransform>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0">Label 1 Second:</Label>
<TextBox Grid.Column="1" Grid.Row="0" Text="TextBox 1 second" />
<Label Grid.Column="0" Grid.Row="1">Label 2 Second:</Label>
<TextBox Grid.Column="1" Grid.Row="1" Text="TextBox 2 second" />
<Button Name="_showMain" Content="Show Main" Grid.Column="1" Grid.Row="3" Click="_showMain_Click" />
</Grid>
</StackPanel>
</Window>
code-behind
namespace WpfAnimationProblem
{
/// <summary>
/// Interaction logic for Window4.xaml
/// </summary>
public partial class Window4 : Window
{
public Window4()
{
InitializeComponent();
}
private void _showSecond_Click(object sender, RoutedEventArgs e)
{
_secondGrid.Visibility = Visibility.Visible;
DisableOtherGrids("_mainGrid");
Storyboard showSecond = this.Resources["_storyboardShowSecond"] as Storyboard;
showSecond.Completed += new EventHandler(showSecond_Completed);
showSecond.Begin();
}
void showSecond_Completed(object sender, EventArgs e)
{
_mainGrid.Visibility = Visibility.Collapsed;
DisableOtherGrids("_secondGrid");
}
private void DisableOtherGrids(string gridName)
{
StackPanel p = this.Content as StackPanel;
foreach (UIElement item in p.Children)
{
if (item is Grid)
{
item.IsEnabled = ((Grid)item).Name == gridName;
}
}
}
private void _showMain_Click(object sender, RoutedEventArgs e)
{
_mainGrid.Visibility = Visibility.Visible;
DisableOtherGrids("_secondGrid");
Storyboard showMain = this.Resources["_storyboardHideSecond"] as Storyboard;
showMain.Completed += new EventHandler(showMain_Completed);
showMain.Begin();
}
void showMain_Completed(object sender, EventArgs e)
{
_secondGrid.Visibility = Visibility.Collapsed;
DisableOtherGrids("_mainGrid");
}
private void StoryboardShowSecond_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardShowSecond_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.CurrentTime, myClock.CurrentState));
}
private void StoryboardShowSecondMT_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardShowSecondMT_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.Parent.CurrentTime, myClock.CurrentState));
}
private void StoryboardShowSecondST_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardShowSecondST_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.Parent.CurrentTime, myClock.CurrentState));
}
private void StoryboardHideSecond_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardHideSecond_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.CurrentTime, myClock.CurrentState));
}
private void StoryboardHideSecondMT_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardHideSecondMT_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.Parent.CurrentTime, myClock.CurrentState));
}
private void StoryboardHideSecondST_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myClock = sender as Clock;
Debug.WriteLine(String.Format("StoryboardHideSecondST_CurrentStateInvalidated Time: {0}, State: {1}",
myClock.Parent.CurrentTime, myClock.CurrentState));
}
}
}
Evan Chua-Yap
Saturday, October 25, 2008 2:26 PM -
It seems that a Clock cannot be used to determine if an animation is running. Maybe we take the wrong approch? Is the another way to find out if an animation is running?
Norbert Ruessmann
Monday, October 27, 2008 11:39 AM -
well you know you can define handlers for two events: CurrentStateInvalidated and CompletedIn your CurrentStateInvalidated handler you can flag when your storyboard's current state changed to active.if (myClock.CurrentState == ClockState.Active)storyBoardHasChangedToActiveState = true; //otherwise false and reset to false at appropriate places in your codeIn your Completed handler, you can flag when your storyboard raised this completed event.storyBoardHasCompleted = false by default (and reset to false at appropriate places in your code)but when your handler is called, storyBoardHasCompleted must be given a value of truelogically, your isStoryboardActive = storyBoardHasChangedToActiveState && !storyBoardHasCompleted.Wouldn't this work if you just use this logic?something like,private bool IsAnimationRunning{get { return storyBoardHasChangedToActiveState && !storyBoardHasCompleted; }}i don't have time to test this out but i think it should work. lMonday, October 27, 2008 7:53 PM