title: Transistion from clockwise to counter-clockwise modes smoothly using WPF storyboard
body: <p><strong>Edit: The project can be downloaded from <a href="https://skydrive.live.com/redir?resid=95D1BB2065E34E8A!3572&amp;authkey=!AIaFLR5V4S6i4ho" rel="nofollow noreferrer">here</a>.</strong></p>
  
  <p>I am using WPF Storyboard to animate the Earth rotation, and I want to be able to reverse the rotation from clockwise to counter-clockwise (and vice versa) when user clicks a button, although in reality this should never happen.</p>
  
  <p><img src="https://i.stack.imgur.com/1eqZC.png" alt="enter image description here"></p>
  
  <p>In my XAML file, I declare 21 BitmapImages (the first and the last are identical) and 2 Storyboards, one for clockwisely rotation and the other for counter-clockwisely rotation.</p>
  
  <pre><code>&lt;Window x:Class="StackOverflowWPF.StoryboardSeekWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="StoryboardSeekWindow" Height="400" Width="400"&gt;
  &lt;Window.Resources&gt;
      &lt;BitmapImage x:Key="RotationImage0" UriSource="Images\rotation\0.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage1" UriSource="Images\rotation\1.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage2" UriSource="Images\rotation\2.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage3" UriSource="Images\rotation\3.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage4" UriSource="Images\rotation\4.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage5" UriSource="Images\rotation\5.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage6" UriSource="Images\rotation\6.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage7" UriSource="Images\rotation\7.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage8" UriSource="Images\rotation\8.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage9" UriSource="Images\rotation\9.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage10" UriSource="Images\rotation\10.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage11" UriSource="Images\rotation\11.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage12" UriSource="Images\rotation\12.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage13" UriSource="Images\rotation\13.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage14" UriSource="Images\rotation\14.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage15" UriSource="Images\rotation\15.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage16" UriSource="Images\rotation\16.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage17" UriSource="Images\rotation\17.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage18" UriSource="Images\rotation\18.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage19" UriSource="Images\rotation\19.png"/&gt;
      &lt;BitmapImage x:Key="RotationImage20" UriSource="Images\rotation\20.png"/&gt;
      &lt;Storyboard x:Key="clockwiseStoryboard" RepeatBehavior="Forever"&gt;
          &lt;ObjectAnimationUsingKeyFrames Storyboard.TargetName="imgRotatingEarth" Storyboard.TargetProperty="Source"&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.0" Value="{Binding Source={StaticResource RotationImage0}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="{Binding Source={StaticResource RotationImage1}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{Binding Source={StaticResource RotationImage2}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.6" Value="{Binding Source={StaticResource RotationImage3}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{Binding Source={StaticResource RotationImage4}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.0" Value="{Binding Source={StaticResource RotationImage5}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.2" Value="{Binding Source={StaticResource RotationImage6}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.4" Value="{Binding Source={StaticResource RotationImage7}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.6" Value="{Binding Source={StaticResource RotationImage8}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.8" Value="{Binding Source={StaticResource RotationImage9}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.0" Value="{Binding Source={StaticResource RotationImage10}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.2" Value="{Binding Source={StaticResource RotationImage11}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.4" Value="{Binding Source={StaticResource RotationImage12}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.6" Value="{Binding Source={StaticResource RotationImage13}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.8" Value="{Binding Source={StaticResource RotationImage14}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.0" Value="{Binding Source={StaticResource RotationImage15}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.2" Value="{Binding Source={StaticResource RotationImage16}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.4" Value="{Binding Source={StaticResource RotationImage17}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.6" Value="{Binding Source={StaticResource RotationImage18}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.8" Value="{Binding Source={StaticResource RotationImage19}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:4.0" Value="{Binding Source={StaticResource RotationImage20}}"/&gt;
          &lt;/ObjectAnimationUsingKeyFrames&gt;
      &lt;/Storyboard&gt;
  
      &lt;Storyboard x:Key="counterClockwiseStoryboard" RepeatBehavior="Forever"&gt;
          &lt;ObjectAnimationUsingKeyFrames Storyboard.TargetName="imgRotatingEarth" Storyboard.TargetProperty="Source"&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.0" Value="{Binding Source={StaticResource RotationImage20}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="{Binding Source={StaticResource RotationImage19}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{Binding Source={StaticResource RotationImage18}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.6" Value="{Binding Source={StaticResource RotationImage17}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{Binding Source={StaticResource RotationImage16}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.0" Value="{Binding Source={StaticResource RotationImage15}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.2" Value="{Binding Source={StaticResource RotationImage14}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.4" Value="{Binding Source={StaticResource RotationImage13}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.6" Value="{Binding Source={StaticResource RotationImage12}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:1.8" Value="{Binding Source={StaticResource RotationImage11}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.0" Value="{Binding Source={StaticResource RotationImage10}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.2" Value="{Binding Source={StaticResource RotationImage9}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.4" Value="{Binding Source={StaticResource RotationImage8}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.6" Value="{Binding Source={StaticResource RotationImage7}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:2.8" Value="{Binding Source={StaticResource RotationImage6}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.0" Value="{Binding Source={StaticResource RotationImage5}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.2" Value="{Binding Source={StaticResource RotationImage4}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.4" Value="{Binding Source={StaticResource RotationImage3}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.6" Value="{Binding Source={StaticResource RotationImage2}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:3.8" Value="{Binding Source={StaticResource RotationImage1}}"/&gt;
              &lt;DiscreteObjectKeyFrame KeyTime="0:0:4.0" Value="{Binding Source={StaticResource RotationImage0}}"/&gt;
          &lt;/ObjectAnimationUsingKeyFrames&gt;
      &lt;/Storyboard&gt;
  &lt;/Window.Resources&gt;
  &lt;Grid&gt;
      &lt;Image x:Name="imgRotatingEarth" HorizontalAlignment="Center" Margin="50" Stretch="Uniform" /&gt;
  
      &lt;Button VerticalAlignment="Bottom" Content="Reverse" Height="30" Width="100" Click="reverseButton_Click" /&gt;
  &lt;/Grid&gt;
  </code></pre>
  
  <p></p>
  
  <p>and my code behind file</p>
  
  <pre><code>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.Shapes;
  using System.Windows.Media.Animation;
  
  namespace StackOverflowWPF
  {
      /// &lt;summary&gt;
      /// Interaction logic for StoryboardSeekWindow.xaml
      /// &lt;/summary&gt;
      public partial class StoryboardSeekWindow : Window
      {
          Storyboard clockwiseStoryboard;
          Storyboard counterClockwiseStoryboard;
          bool bRotateClockwisely;
          TimeSpan duration = new TimeSpan(0, 0, 4);
          double dProgress = 0; //the value of dProgress is from 0.0 (begin) to 1.0 (end)
  
          public StoryboardSeekWindow()
          {
              InitializeComponent();
              clockwiseStoryboard = this.FindResource("clockwiseStoryboard") as Storyboard;
              counterClockwiseStoryboard = this.FindResource("counterClockwiseStoryboard") as Storyboard;
              StartRotation();
          }
  
          private void StartRotation()
          {
              counterClockwiseStoryboard.Begin();
              counterClockwiseStoryboard.Pause();
  
              clockwiseStoryboard.Begin();
  
              bRotateClockwisely = true;
          }
  
          private void reverseButton_Click(object sender, RoutedEventArgs e)
          {
              Storyboard sbActive = bRotateClockwisely ? clockwiseStoryboard : counterClockwiseStoryboard;
              Storyboard sbPaused = bRotateClockwisely ? counterClockwiseStoryboard : clockwiseStoryboard;
  
              sbActive.Pause();
  
              //I want the other storyboard can seek to where the animation is paused.
              dProgress = sbActive.GetCurrentProgress();
              dProgress = 1.0 - dProgress;
              sbPaused.Seek(new TimeSpan((long)(duration.Ticks * dProgress)));
  
              sbPaused.Resume();
  
              bRotateClockwisely = !bRotateClockwisely;            
          }
      }
  }
  </code></pre>
  
  <p>In order to get a smooth transition from clockwise to counter-clockwise mode, I pause the active animation and calculate which frame I am in, when resume the reverse animation, I first seek to that frame. In order words, I want to achieve the effect.</p>
  
  <p>0.png->1.png->2.png->3.png->4.png->5.png-><strong>user clicks button</strong>->5.png->4.png->3.png->2.png->1.png->0.png->... </p>
  
  <p>But my code does not work. The Storyboard.Seek() seems to be working, but it does not start rotating reversely. I think I might be wrong in running 2 storyboards to manipulate the same object. </p>
  
  <p>Could someone help me to fix the bugs, and perhaps provide a better idea to achieve the same effect?</p>