/// <summary> /// Slides the drag indicator (item snapshot) to the location of the dropped item, /// then performs the visibility swap and removes the dragging visual state. /// </summary> private void AnimateDrop(ReorderListBoxItem itemContainer) { GeneralTransform itemTransform = itemContainer.TransformToVisual(this.dragInterceptor); Rect itemRect = itemTransform.TransformBounds(new Rect(new Point(0, 0), itemContainer.RenderSize)); double delta = Math.Abs(itemRect.Y - Canvas.GetTop(this.dragIndicator) - ((TranslateTransform)this.dragIndicator.RenderTransform).Y); if (delta > 0) { // Adjust the duration based on the distance, so the speed will be constant. TimeSpan duration = TimeSpan.FromSeconds(0.25 * delta / itemRect.Height); Storyboard dropStoryboard = new Storyboard(); DoubleAnimation moveToDropAnimation = new DoubleAnimation(); Storyboard.SetTarget(moveToDropAnimation, this.dragIndicator.RenderTransform); Storyboard.SetTargetProperty(moveToDropAnimation, new PropertyPath(TranslateTransform.YProperty)); moveToDropAnimation.To = itemRect.Y - Canvas.GetTop(this.dragIndicator); moveToDropAnimation.Duration = duration; dropStoryboard.Children.Add(moveToDropAnimation); dropStoryboard.Completed += delegate { this.dragItem = null; itemContainer.Opacity = 1; this.dragIndicator.Visibility = Visibility.Collapsed; this.dragIndicator.Source = null; ((TranslateTransform)this.dragIndicator.RenderTransform).Y = 0; VisualStateManager.GoToState(itemContainer, ReorderListBoxItem.NotDraggingState, true); }; dropStoryboard.Begin(); } else { // There was no need for an animation, so do the visibility swap right now. this.dragItem = null; itemContainer.Opacity = 1; this.dragIndicator.Visibility = Visibility.Collapsed; this.dragIndicator.Source = null; VisualStateManager.GoToState(itemContainer, ReorderListBoxItem.NotDraggingState, true); } }