private void MoveGhostToMousePosition( Point mousePosition )
    {
      // Ensure the opacity of the ghost is correctly set
      this.ShowDraggedColumnGhosts();

      Point currentAdornerPosition = mousePosition;

      if( m_elementToDraggedElementAdorner.Count == 0 )
        return;

      int remainingDuration = this.ReturnToOriginalPositionDuration;

      if( m_ghostToMousePositionAnimationClock != null )
      {
        PointAnimation pointAnimation = m_ghostToMousePositionAnimationClock.Timeline as PointAnimation;

        Point currentValue = pointAnimation.To.GetValueOrDefault();

        double deltaX = currentValue.X - mousePosition.X;
        double deltaY = currentValue.Y - mousePosition.Y;

        bool dragingX = Math.Abs( deltaX ) > SystemParameters.MinimumHorizontalDragDistance;
        bool dragingY = Math.Abs( deltaY ) > SystemParameters.MinimumVerticalDragDistance;

        // If the target value is already the correct one, no need to stop animation and create another one
        if( ( pointAnimation != null ) && ( !dragingX && !dragingY ) )
        {
          return;
        }
        else
        {
          if( m_ghostToMousePositionAnimationClock.CurrentState == ClockState.Active )
          {
            // The remaining duration is the Timeline Duration less the elapsed time
            remainingDuration = pointAnimation.Duration.TimeSpan.Milliseconds - m_ghostToMousePositionAnimationClock.CurrentTime.Value.Milliseconds;
          }
        }
      }

      this.PauseGhostToMousePositionAnimation();

      PointAnimation animation = new PointAnimation( currentAdornerPosition, mousePosition, new Duration( TimeSpan.FromMilliseconds( remainingDuration ) ) );

      m_ghostToMousePositionAnimationClock = animation.CreateClock( true ) as AnimationClock;
      m_ghostToMousePositionAnimationClock.Completed += this.GhostToMousePosition_Completed;

      foreach( var adorner in this.GetElementAdorners() )
      {
        adorner.ApplyAnimationClock( DraggedElementAdorner.OffsetProperty, m_ghostToMousePositionAnimationClock, HandoffBehavior.SnapshotAndReplace );
      }

      m_ghostToMousePositionAnimationClock.Controller.Begin();
    }
    private void MoveGhostToTargetColumn( Point mousePostion )
    {
      if( m_elementToDraggedElementAdorner.Count == 0 )
        return;

      int remainingDuration = this.ReturnToOriginalPositionDuration;

      if( m_ghostToTargetColumnAnimationClock != null )
      {
        PointAnimation pointAnimation = m_ghostToTargetColumnAnimationClock.Timeline as PointAnimation;

        // If the target value is already the correct one, no need to stop animation and create another one
        if( ( pointAnimation != null ) && ( pointAnimation.To == ColumnReorderingDragSourceManager.EmptyPoint ) )
        {
          return;
        }
        else
        {
          if( m_ghostToTargetColumnAnimationClock.CurrentState == ClockState.Active )
          {
            // The remaining duration is the Timeline Duration less the elapsed time
            remainingDuration = pointAnimation.Duration.TimeSpan.Milliseconds - m_ghostToTargetColumnAnimationClock.CurrentTime.Value.Milliseconds;
          }
        }
      }

      // We must apply the DraggedCell FadeIn animation to let the DraggedCell reappears while the ghosts are moving to their target position
      this.ApplyDraggedElementFadeInAnimation();

      this.PauseMoveGhostToTargetColumnAnimation();

      PointAnimation animation = new PointAnimation( mousePostion, ColumnReorderingDragSourceManager.EmptyPoint, new Duration( TimeSpan.FromMilliseconds( remainingDuration ) ) );

      m_ghostToTargetColumnAnimationClock = animation.CreateClock( true ) as AnimationClock;
      m_ghostToTargetColumnAnimationClock.Completed += this.GhostToTargetAnimation_Completed;

      foreach( var adorner in this.GetElementAdorners() )
      {
        adorner.ApplyAnimationClock( DraggedElementAdorner.OffsetProperty, m_ghostToTargetColumnAnimationClock, HandoffBehavior.SnapshotAndReplace );
      }
    }
    private void MoveGhostToTargetAndDetach()
    {
      if( m_elementToDraggedElementAdorner.Count == 0 )
      {
        this.DetachManager();
        return;
      }

      this.PauseMoveGhostToTargetAndDetachAnimation();

      var draggedCell = this.DraggedElement as Cell;
      if( draggedCell == null )
        return;

      var parentRow = draggedCell.ParentRow;
      if( ( parentRow == null ) || ( parentRow.CellsHostPanel == null ) )
        return;

      var draggedAdorner = m_elementToDraggedElementAdorner[ draggedCell ];
      var currentDraggedAdornerPosition = ( draggedAdorner != null ) ? draggedAdorner.Offset : default( Point );
      var fromPoint = currentDraggedAdornerPosition;

      if( draggedAdorner != null )
      {
        // Calculate the animation from the current ColumnManagerCell, since it could be a MergedColumnMangerCell dragging any number of columns.
        // If calculating the animation from a different cell, the animation could be starting from a wrong position and give a bad visual effect.
        var animations = this.ReorderingInfoManagerInstance.RequiredAnimations;
        if( animations.AnimateToLeft.Count > 0 )
        {
          var siblingCell = parentRow.Cells[ draggedCell.ParentColumn.PreviousVisibleColumn ];
          var targetPosition = siblingCell.PointToScreen( new Point( siblingCell.ActualWidth, 0d ) );
          var relativePosition = draggedAdorner.PointFromScreen( targetPosition );

          fromPoint = new Point( -relativePosition.X, -relativePosition.Y );
        }
        else if( animations.AnimateToRight.Count > 0 )
        {
          var siblingCell = parentRow.Cells[ draggedCell.ParentColumn.NextVisibleColumn ];
          var targetPosition = siblingCell.PointToScreen( new Point( -draggedCell.ActualWidth, 0d ) );
          var relativePosition = draggedAdorner.PointFromScreen( targetPosition );

          fromPoint = new Point( -relativePosition.X, -relativePosition.Y );
        }
      }

      PointAnimation animation = new PointAnimation( fromPoint, ColumnReorderingDragSourceManager.EmptyPoint, m_columnAnimationDuration );

      m_ghostToTargetAndDetachAnimationClock = animation.CreateClock( true ) as AnimationClock;
      m_ghostToTargetAndDetachAnimationClock.Completed += this.MoveGhostToTargetAndDetach_Completed;

      //Animate all cells of all columns.
      foreach( var entry in this.GetElementAdornerEntries() )
      {
        var cell = entry.Key as Cell;
        if( cell == null )
        {
          Debug.Assert( false, "Only Cells should be dragged by this manager" );
          continue;
        }

        var adorner = entry.Value;
        adorner.ApplyAnimationClock( DraggedElementAdorner.OffsetProperty, m_ghostToTargetAndDetachAnimationClock, HandoffBehavior.SnapshotAndReplace );
      }

      m_ghostToTargetAndDetachAnimationClock.Controller.Begin();
    }
    private void MoveGhostToTargetAndDetach()
    {
      if( m_elementToDraggedElementAdorner.Count == 0 )
      {
        this.DetachManager();
        return;
      }

      this.PauseMoveGhostToTargetAndDetachAnimation();

      Cell draggedCell = this.DraggedElement as Cell;

      if( draggedCell == null )
        return;

      bool animationInitialized = false;

      DraggedElementAdorner draggedAdorner = m_elementToDraggedElementAdorner[ draggedCell ];

      Nullable<Point> currentDraggedAdornerPosition = null;

      if( draggedAdorner != null )
      {
        currentDraggedAdornerPosition = draggedAdorner.Offset;
      }

      foreach( UIElement element in m_elementToDraggedElementAdorner.Keys )
      {
        Cell cell = element as Cell;

        if( cell == null )
        {
          Debug.Assert( false, "Only Cells should be dragged by this manager" );
          continue;
        }

        DraggedElementAdorner adorner = m_elementToDraggedElementAdorner[ element ];

        if( !animationInitialized )
        {
          TableViewColumnVirtualizationManager columnVirtualizationManager = this.DraggedDataGridContext.ColumnVirtualizationManager as TableViewColumnVirtualizationManager;

          if( columnVirtualizationManager == null )
            return;

          double offset = columnVirtualizationManager.FieldNameToOffset[ draggedCell.FieldName ];

          if( ( draggedCell.ParentRow == null ) || ( draggedCell.ParentRow.CellsHostPanel == null ) )
            return;

          // Get the position of the Mouse according to the DragContainer
          Point mouseToDragContainer = Mouse.GetPosition( this.DragContainer );

          // Get the position of the Mouse according to the DraggedElementAdorner
          Point adornerToMouse = Mouse.GetPosition( adorner );

          // Get the position of the Cell according to the ParentRow.CellsHostPanel for the dragged Cell
          Panel cellsHost = cell.ParentRow.CellsHostPanel;
          Point newCellInCellsHostToDragContainer = cellsHost.TranslatePoint( new Point( offset, 0 ), this.DragContainer );

          // Get the position of the Cell according to its CellsHost in order to know
          // if it was dragged from the Fixed to the Scrolling Cells.
          Point cellToCellsHost = cell.TranslatePoint( ColumnReorderingDragSourceManager.EmptyPoint, cell.ParentRow.CellsHostPanel );

          double initialX = mouseToDragContainer.X - newCellInCellsHostToDragContainer.X - adornerToMouse.X;

          // The DraggedCell is a FixedCell and it offset is greater than  the FixedColumnWidth
          if( columnVirtualizationManager.FixedFieldNames.Contains( cell.FieldName ) && ( cellToCellsHost.X > columnVirtualizationManager.FixedColumnsWidth ) )
          {
            // In this case, we must take the HorizontalOffset into consideration
            initialX -= this.DraggedDataGridContext.DataGridControl.ScrollViewer.HorizontalOffset;
          }
          else
          {
            // The offset of the Cell according the CellsHost is less than 0 and
            // there is a Compensation offset to ensure all the ScrollingCells are
            // in view even if the HorizontalOffset would have scrolled them
            // outside the ViewPort
            if( ( ( newCellInCellsHostToDragContainer.X - columnVirtualizationManager.FixedColumnsWidth ) < 0 ) && ( columnVirtualizationManager.FirstColumnCompensationOffset > 0 ) )
            {
              initialX -= columnVirtualizationManager.FirstColumnCompensationOffset;
            }
          }

          Point fromPoint = new Point( initialX, currentDraggedAdornerPosition.GetValueOrDefault().Y );

          PointAnimation animation = new PointAnimation( fromPoint, ColumnReorderingDragSourceManager.EmptyPoint, m_columnAnimationDuration );

          m_ghostToTargetAndDetachAnimationClock = animation.CreateClock( true ) as AnimationClock;
          m_ghostToTargetAndDetachAnimationClock.Completed += this.MoveGhostToTargetAndDetach_Completed;

          animationInitialized = true;
        }

        adorner.ApplyAnimationClock( DraggedElementAdorner.OffsetProperty, m_ghostToTargetAndDetachAnimationClock, HandoffBehavior.SnapshotAndReplace );
      }

      m_ghostToTargetAndDetachAnimationClock.Controller.Begin();
    }