private void dragInterceptor_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
if (this.Items.Count <= 1 || this.dragItem == null)
{
return;
}
if (this.dropTargetIndex == -1)
{
if (this.dragItemContainer == null)
{
return;
}
// When the drag actually starts, swap out the item for the drag-indicator image of the item.
// This is necessary because the item itself may be removed from the virtualizing panel
// if the drag causes a scroll of considerable distance.
Size dragItemSize = this.dragItemContainer.RenderSize;
WriteableBitmap writeableBitmap = new WriteableBitmap(
(int)dragItemSize.Width, (int)dragItemSize.Height);
// Swap states to force the transition to complete.
VisualStateManager.GoToState(this.dragItemContainer, ReorderListBoxItem.NotDraggingState, false);
VisualStateManager.GoToState(this.dragItemContainer, ReorderListBoxItem.DraggingState, false);
writeableBitmap.Render(this.dragItemContainer, null);
writeableBitmap.Invalidate();
this.dragIndicator.Source = writeableBitmap;
this.dragIndicator.Visibility = Visibility.Visible;
this.dragItemContainer.Visibility = Visibility.Collapsed;
if (this.itemsPanel.Children.IndexOf(this.dragItemContainer) < this.itemsPanel.Children.Count - 1)
{
this.UpdateDropTarget(Canvas.GetTop(this.dragIndicator) + this.dragIndicator.Height + 1, false);
}
else
{
this.UpdateDropTarget(Canvas.GetTop(this.dragIndicator) - 1, false);
}
}
double dragItemHeight = this.dragIndicator.Height;
TranslateTransform translation = (TranslateTransform)this.dragIndicator.RenderTransform;
double top = Canvas.GetTop(this.dragIndicator);
// Limit the translation to keep the item within the list area.
// Use different targeting for the top and bottom edges to allow taller items to
// move before or after shorter items at the edges.
double y = top + e.CumulativeManipulation.Translation.Y;
if (y < 0)
{
y = 0;
this.UpdateDropTarget(0, true);
}
else if (y >= this.dragInterceptorRect.Height - dragItemHeight)
{
y = this.dragInterceptorRect.Height - dragItemHeight;
this.UpdateDropTarget(this.dragInterceptorRect.Height - 1, true);
}
else
{
this.UpdateDropTarget(y + dragItemHeight / 2, true);
}
translation.Y = y - top;
// Check if we're within the margin where auto-scroll needs to happen.
bool scrolling = (this.dragScrollDelta != 0);
double autoScrollMargin = this.AutoScrollMargin;
if (autoScrollMargin > 0 && y < autoScrollMargin)
{
this.dragScrollDelta = y - autoScrollMargin;
if (!scrolling)
{
VisualStateManager.GoToState(this.scrollViewer, ReorderListBox.ScrollViewerScrollingVisualState, true);
this.Dispatcher.BeginInvoke(() => this.DragScroll());
return;
}
}
else if (autoScrollMargin > 0 && y + dragItemHeight > this.dragInterceptorRect.Height - autoScrollMargin)
{
this.dragScrollDelta = (y + dragItemHeight - (this.dragInterceptorRect.Height - autoScrollMargin));
if (!scrolling)
{
VisualStateManager.GoToState(this.scrollViewer, ReorderListBox.ScrollViewerScrollingVisualState, true);
this.Dispatcher.BeginInvoke(() => this.DragScroll());
return;
}
}
else
{
// We're not within the auto-scroll margin. This ensures any current scrolling is stopped.
this.dragScrollDelta = 0;
}
}