private void ApplyDraggedElementFadeInAnimation()
    {
      int remainingOpacityDuration = this.DraggedElementFadeInDuration;

      if( m_draggedElementFadeInAnimationClock != null )
      {
        OffsetAnimation fadeInAnimation = m_draggedElementFadeInAnimationClock.Timeline as OffsetAnimation;

        if( ( fadeInAnimation != null ) && ( fadeInAnimation.To == 1d ) )
        {
          return;
        }
        else
        {
          if( m_draggedElementFadeInAnimationClock.CurrentState == ClockState.Active )
          {
            // The remaining duration is the Timeline Duration less the elapsed time
            remainingOpacityDuration = fadeInAnimation.Duration.TimeSpan.Milliseconds - m_draggedElementFadeInAnimationClock.CurrentTime.Value.Milliseconds;
          }
        }
      }

      this.PauseDraggedElementFadeInAnimation();

      UIElement draggedElement = this.DraggedElement;

      // Apply an animation on the opacity of the Cell to ensure a nice transition between the ColumnReordering and another IDropTarget that is not handled by this manager
      if( draggedElement != null )
      {
        OffsetAnimation opacityAnimation = new OffsetAnimation( 1, new Duration( TimeSpan.FromMilliseconds( remainingOpacityDuration ) ) );

        m_draggedElementFadeInAnimationClock = opacityAnimation.CreateClock( true ) as AnimationClock;

        // We ust the same completed callback as MoveGhostToTarget animation to  be sure that the DraggedElement
        // FadeIn is completed and the ghosts are correctly positioned before displaying the original UIElements
        m_draggedElementFadeInAnimationClock.Completed += this.GhostToTargetAnimation_Completed;

        draggedElement.ApplyAnimationClock( UIElement.OpacityProperty, m_draggedElementFadeInAnimationClock );

        m_draggedElementFadeInAnimationClock.Controller.Begin();
      }
    }
    private void DoSplitterAnimation( double offset, bool isReverting )
    {
      if( m_splitterAnimationClock != null )
      {
        OffsetAnimation clockOffsetAnimation = m_splitterAnimationClock.Timeline as OffsetAnimation;

        // If the target value is already the correct one, no need to stop animation and create another one
        if( ( clockOffsetAnimation != null ) && ( clockOffsetAnimation.To == offset ) )
          return;
      }

      this.PauseSplitterAnimation();

      OffsetAnimation animation = new OffsetAnimation( offset, m_columnAnimationDuration );
      m_splitterAnimationClock = ( AnimationClock )animation.CreateClock( true );

      this.FixedColumnSplitterTranslation.ApplyAnimationClock( TranslateTransform.XProperty, m_splitterAnimationClock, HandoffBehavior.SnapshotAndReplace );

      if( isReverting )
      {
        m_splitterAnimationClock.Completed += this.RollbackSplitterAnimationCompleted;
      }

      m_splitterAnimationClock.Controller.Begin();
    }
    private void DoColumnAnimation( ColumnBase column, double toValue, Duration duration, bool isReverting )
    {
      if( column == null )
        return;

      // Never animate the dragged Column to avoid flickering effects on the ghosts because we compute its position on each MouseMove event
      Cell draggedCell = this.DraggedElement as Cell;
      if( ( draggedCell != null ) && ( column == draggedCell.ParentColumn ) )
        return;

      TranslateTransform positionTransform = ColumnReorderingDragSourceManager.GetAnimatedColumnReorderingPositionTransform( column );
      List<AnimationClock> animationClocks;
      AnimationClock positionAnimationClock = null;

      // Pause previously applied AnimationClock
      if( m_fieldNameToClock.TryGetValue( column, out animationClocks ) )
      {
        // If the target value is already the correct one, no need to stop animation and create another one
        positionAnimationClock = animationClocks[ 0 ];
        OffsetAnimation positionTimeLine = positionAnimationClock.Timeline as OffsetAnimation;
        if( ( positionTimeLine != null ) && ( positionTimeLine.To == toValue ) )
          return;

        // Stop the animation, do not simply pause it, so it resets correctly.
        positionAnimationClock.Controller.Stop();
        positionAnimationClock.Completed -= this.ColumnAnimationCompleted;

        m_fieldNameToClock.Remove( column );
      }

      OffsetAnimation positionAnimation = new OffsetAnimation( toValue, duration );
      positionAnimationClock = positionAnimation.CreateClock( true ) as AnimationClock;
      positionTransform.ApplyAnimationClock( TranslateTransform.XProperty, positionAnimationClock, HandoffBehavior.SnapshotAndReplace );

      //Since we are dealing with regular Columns (i.e. not MergedColumns), no need for resize animation, so we can simply store a null value for the resize AnimationClock.
      m_fieldNameToClock.Add( column, new List<AnimationClock>() { positionAnimationClock, null } );

      if( isReverting )
      {
        positionAnimationClock.Completed += this.ColumnAnimationCompleted;
      }

      //Start the animation
      positionAnimationClock.Controller.Begin();
    }
    private void InitializeVerticalOffsetAnimation()
    {
      if( m_verticalOffsetAnimation != null )
        return;

      m_verticalOffsetAnimation = new OffsetAnimation();
    }
    private void InitializeHorizontalOffsetAnimation()
    {
      if( m_horizontalOffsetAnimation != null )
        return;

      m_horizontalOffsetAnimation = new OffsetAnimation();
    }
    private AnimationClock DoColumnAnimation( ColumnBase column, double toValue, Duration duration, bool isReverting )
    {
      if( column == null )
        return null;

      Cell draggedCell = this.DraggedElement as Cell;

      // Never animate the dragged Column to avoid flickering
      // effects on the ghosts because we compute its position
      // on each MouseMove event
      if( ( draggedCell != null ) && ( column == draggedCell.ParentColumn ) )
        return null;

      TranslateTransform transform = ColumnReorderingDragSourceManager.GetAnimatedColumnReorderingTranslation( column );

      if( transform == null )
      {
        transform = new TranslateTransform();
        ColumnReorderingDragSourceManager.SetAnimatedColumnReorderingTranslation( column, transform );
      }

      string fieldName = column.FieldName;

      AnimationClock animationClock = null;

      // Pause previously applied AnimationClock
      if( m_fieldNameToClock.TryGetValue( fieldName, out animationClock ) )
      {
        OffsetAnimation clockOffsetAnimation = animationClock.Timeline as OffsetAnimation;

        // If the target value is already the correct one, no need to stop animation and create another one
        if( ( clockOffsetAnimation != null ) && ( clockOffsetAnimation.To == toValue ) )
          return animationClock;

        // Stop the animation, do not simply pause it, so it resets correctly.
        animationClock.Controller.Stop();
        animationClock.Completed -= this.ColumnAnimationCompleted;

        m_fieldNameToClock.Remove( fieldName );
        m_clockToFieldName.Remove( animationClock );
      }

      OffsetAnimation animation = new OffsetAnimation( toValue, duration );
      animationClock = animation.CreateClock( true ) as AnimationClock;

      transform.ApplyAnimationClock( TranslateTransform.XProperty, animationClock, HandoffBehavior.SnapshotAndReplace );

      m_fieldNameToClock.Add( fieldName, animationClock );
      m_clockToFieldName.Add( animationClock, fieldName );

      if( isReverting )
      {
        animationClock.Completed += this.ColumnAnimationCompleted;
      }

      animationClock.Controller.Begin();

      return animationClock;
    }