locked
How can I find out if a Storyboard is active? RRS feed

  • 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(thistrue); 
            } 
     
            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

    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.aspx
    Please 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



    Saturday, October 25, 2008 2:08 PM

All replies

  • try

    ClockGroup sbClock = sb.CreateClock();

    then to test, access sbClock.CurrentState

    hope this helps

    evan chua-yap
    Friday, 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

    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.aspx
    Please 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



    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 Completed

    In 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 code

    In 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 true

    logically, 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.  l
    Monday, October 27, 2008 7:53 PM