private void AnimateRearrangeInternal(Action rearrangeAction, Duration animationDuration)
{
// Find the indices of items in the view. Animations are optimzed to only include what is visible.
int viewFirstIndex, viewLastIndex;
this.GetViewIndexRange(true, out viewFirstIndex, out viewLastIndex);
// Collect information about items and their positions before any changes are made.
RearrangeItemInfo[] rearrangeMap = this.BuildRearrangeMap(viewFirstIndex, viewLastIndex);
// Call the rearrange action callback which actually makes the changes to the source list.
// Assuming the source list is properly bound, the base class will pick up the changes.
rearrangeAction();
this.rearrangeCanvas.Visibility = Visibility.Visible;
// Update the layout (positions of all items) based on the changes that were just made.
this.UpdateLayout();
// Find the NEW last-index in view, which may have changed if the items are not constant heights
// or if the view includes the end of the list.
viewLastIndex = this.FindViewLastIndex(viewFirstIndex);
// Collect information about the NEW items and their NEW positions, linking up to information
// about items which existed before.
RearrangeItemInfo[] rearrangeMap2 = this.BuildRearrangeMap2(rearrangeMap,
viewFirstIndex, viewLastIndex);
// Find all the movements that need to be animated.
IEnumerable<RearrangeItemInfo> movesWithinView = rearrangeMap
.Where(rii => !Double.IsNaN(rii.FromY) && !Double.IsNaN(rii.ToY));
IEnumerable<RearrangeItemInfo> movesOutOfView = rearrangeMap
.Where(rii => !Double.IsNaN(rii.FromY) && Double.IsNaN(rii.ToY));
IEnumerable<RearrangeItemInfo> movesInToView = rearrangeMap2
.Where(rii => Double.IsNaN(rii.FromY) && !Double.IsNaN(rii.ToY));
IEnumerable<RearrangeItemInfo> visibleMoves =
movesWithinView.Concat(movesOutOfView).Concat(movesInToView);
// Set a clip rect so the animations don't go outside the listbox.
this.rearrangeCanvas.Clip = new RectangleGeometry() { Rect = new Rect(new Point(0, 0), this.rearrangeCanvas.RenderSize) };
// Create the animation storyboard.
Storyboard rearrangeStoryboard = this.CreateRearrangeStoryboard(visibleMoves, animationDuration);
if (rearrangeStoryboard.Children.Count > 0)
{
// The storyboard uses an overlay canvas with item snapshots.
// While that is playing, hide the real items.
this.scrollViewer.Visibility = Visibility.Collapsed;
rearrangeStoryboard.Completed += delegate
{
rearrangeStoryboard.Stop();
this.rearrangeCanvas.Children.Clear();
this.rearrangeCanvas.Visibility = Visibility.Collapsed;
this.scrollViewer.Visibility = Visibility.Visible;
this.AnimateNextRearrange();
};
this.Dispatcher.BeginInvoke(() => rearrangeStoryboard.Begin());
}
else
{
this.rearrangeCanvas.Visibility = Visibility.Collapsed;
this.AnimateNextRearrange();
}
}