/// <summary> /// Updates the targeted index -- that is the index where the item will be moved to if dropped at this point. /// </summary> private void UpdateDropTargetIndex(ReorderListBoxItem targetItemContainer, bool after) { int dragItemIndex = this.Items.IndexOf(this.dragItem); int targetItemIndex = this.Items.IndexOf(targetItemContainer.Content); int newDropTargetIndex; if (targetItemIndex == dragItemIndex) { newDropTargetIndex = dragItemIndex; } else { newDropTargetIndex = targetItemIndex + (after ? 1 : 0) - (targetItemIndex >= dragItemIndex ? 1 : 0); } if (newDropTargetIndex != this.dropTargetIndex) { this.dropTargetIndex = newDropTargetIndex; } }
/// <summary> /// Called when the user presses down on the transparent drag-interceptor. Identifies the targed /// drag handle and list item and prepares for a drag operation. /// </summary> private void dragInterceptor_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { if (this.itemsPanel == null) { ItemsPresenter scrollItemsPresenter = (ItemsPresenter)this.scrollViewer.Content; this.itemsPanel = (Panel)VisualTreeHelper.GetChild(scrollItemsPresenter, 0); } GeneralTransform interceptorTransform = this.dragInterceptor.TransformToVisual( Application.Current.RootVisual); Point targetPoint = interceptorTransform.Transform(e.ManipulationOrigin); targetPoint = ReorderListBox.GetHostCoordinates(targetPoint); List<UIElement> targetElements = VisualTreeHelper.FindElementsInHostCoordinates( targetPoint, this.itemsPanel).ToList(); ReorderListBoxItem targetItemContainer = targetElements.OfType<ReorderListBoxItem>().FirstOrDefault(); if (targetItemContainer != null && targetElements.Contains(targetItemContainer.DragHandle)) { VisualStateManager.GoToState(targetItemContainer, ReorderListBoxItem.DraggingState, true); GeneralTransform targetItemTransform = targetItemContainer.TransformToVisual(this.dragInterceptor); Point targetItemOrigin = targetItemTransform.Transform(new Point(0, 0)); Canvas.SetLeft(this.dragIndicator, targetItemOrigin.X); Canvas.SetTop(this.dragIndicator, targetItemOrigin.Y); this.dragIndicator.Width = targetItemContainer.RenderSize.Width; this.dragIndicator.Height = targetItemContainer.RenderSize.Height; this.dragItemContainer = targetItemContainer; this.dragItem = this.dragItemContainer.Content; this.dragInterceptorRect = interceptorTransform.TransformBounds( new Rect(new Point(0, 0), this.dragInterceptor.RenderSize)); this.dropTargetIndex = -1; } }
/// <summary> /// Ensures that a possibly-recycled item container (ReorderListBoxItem) is ready to display a list item. /// </summary> protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { base.PrepareContainerForItemOverride(element, item); ReorderListBoxItem itemContainer = (ReorderListBoxItem)element; itemContainer.ApplyTemplate(); // Loads visual states. // Set this state before binding to avoid showing the visual transition in this case. string reorderState = this.IsReorderEnabled ? ReorderListBoxItem.ReorderEnabledState : ReorderListBoxItem.ReorderDisabledState; VisualStateManager.GoToState(itemContainer, reorderState, false); itemContainer.SetBinding(ReorderListBoxItem.IsReorderEnabledProperty, new Binding(ReorderListBox.IsReorderEnabledPropertyName) { Source = this }); if (item == this.dragItem) { VisualStateManager.GoToState(itemContainer, ReorderListBoxItem.DraggingState, false); if (this.dropTargetIndex >= 0) { // The item's dragIndicator is currently being moved, so the item itself is hidden. itemContainer.Visibility = Visibility.Collapsed; this.dragItemContainer = itemContainer; } else { // The item was just moved and dropped, so it needs to be transitioned back to not-dragging state. VisualStateManager.GoToState(itemContainer, ReorderListBoxItem.NotDraggingState, true); this.dragItem = null; } } else { VisualStateManager.GoToState(itemContainer, ReorderListBoxItem.NotDraggingState, false); } }
/// <summary> /// Called when the user releases a drag. Moves the item within the source list and then resets everything. /// </summary> private void dragInterceptor_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { if (this.dragItem == null) { return; } this.dragIndicator.Visibility = Visibility.Collapsed; ((TranslateTransform)this.dragIndicator.RenderTransform).Y = 0; this.dragIndicator.Source = null; if (this.dropTargetIndex >= 0) { this.MoveItem(this.dragItem, this.dropTargetIndex); } if (this.dragItemContainer != null) { this.dragItemContainer.Visibility = Visibility.Visible; VisualStateManager.GoToState(this.dragItemContainer, ReorderListBoxItem.NotDraggingState, true); this.dragItemContainer = null; this.dragItem = null; } this.dragScrollDelta = 0; this.dropTargetIndex = -1; this.ClearDropTarget(); }
/// <summary> /// Called when an item container (ReorderListBoxItem) is being removed from the list panel. /// This may be because the item was removed from the list or because the item is now outside /// the virtualization region (because ListBox uses a VirtualizingStackPanel as its items panel). /// </summary> protected override void ClearContainerForItemOverride(DependencyObject element, object item) { base.ClearContainerForItemOverride(element, item); ReorderListBoxItem itemContainer = (ReorderListBoxItem)element; if (itemContainer == this.dragItemContainer) { this.dragItemContainer.Visibility = Visibility.Visible; this.dragItemContainer = null; } }