/// <summary> /// Initializes a new instance of the DragInfo class. /// </summary> /// <param name="sender">The sender of the input event that initiated the drag operation.</param> /// <param name="originalSource">The original source of the input event.</param> /// <param name="mouseButton">The mouse button which was used for the drag operation.</param> /// <param name="getPosition">A function of the input event which is used to get drag position points.</param> public DragInfo(object sender, object originalSource, MouseButton mouseButton, Func <IInputElement, Point> getPosition) { this.MouseButton = mouseButton; this.Effects = DragDropEffects.None; this.VisualSource = sender as UIElement; this.DragStartPosition = getPosition(this.VisualSource); this.DragDropCopyKeyState = DragDrop.GetDragDropCopyKeyState(this.VisualSource); var dataFormat = DragDrop.GetDataFormat(this.VisualSource); if (dataFormat != null) { this.DataFormat = dataFormat; } var sourceElement = originalSource as UIElement; // If we can't cast object as a UIElement it might be a FrameworkContentElement, if so try and use its parent. if (sourceElement == null && originalSource is FrameworkContentElement frameworkContentElement) { sourceElement = frameworkContentElement.Parent as UIElement; } if (sender is ItemsControl itemsControl) { this.SourceGroup = itemsControl.FindGroup(this.DragStartPosition); this.VisualSourceFlowDirection = itemsControl.GetItemsPanelFlowDirection(); UIElement item = null; if (sourceElement != null) { item = itemsControl.GetItemContainer(sourceElement); } if (item == null) { var itemPosition = this.DragStartPosition; if (DragDrop.GetDragDirectlySelectedOnly(this.VisualSource)) { item = itemsControl.GetItemContainerAt(itemPosition); } else { item = itemsControl.GetItemContainerAt(itemPosition, itemsControl.GetItemsPanelOrientation()); if (item.IsDragSourceIgnored()) { item = null; } } } if (item != null) { // Remember the relative position of the item being dragged this.PositionInDraggedItem = getPosition(item); var itemParent = ItemsControl.ItemsControlFromItemContainer(item); if (itemParent != null) { this.SourceCollection = itemParent.ItemsSource ?? itemParent.Items; if (itemParent != itemsControl) { if (item is TreeViewItem tvItem) { var tv = tvItem.GetVisualAncestor <TreeView>(); if (tv != null && tv != itemsControl && !tv.IsDragSource()) { return; } } else if (itemsControl.ItemContainerGenerator.IndexFromContainer(itemParent) < 0 && !itemParent.IsDragSource()) { return; } } this.SourceIndex = itemParent.ItemContainerGenerator.IndexFromContainer(item); this.SourceItem = itemParent.ItemContainerGenerator.ItemFromContainer(item); } else { this.SourceIndex = -1; } var selectedItems = itemsControl.GetSelectedItems().OfType <object>().Where(i => i != CollectionView.NewItemPlaceholder).ToList(); this.SourceItems = selectedItems; // Some controls (I'm looking at you TreeView!) haven't updated their // SelectedItem by this point. Check to see if there 1 or less item in // the SourceItems collection, and if so, override the control's SelectedItems with the clicked item. // // The control has still the old selected items at the mouse down event, so we should check this and give only the real selected item to the user. if (selectedItems.Count <= 1 || this.SourceItem != null && !selectedItems.Contains(this.SourceItem)) { this.SourceItems = Enumerable.Repeat(this.SourceItem, 1); } this.VisualSourceItem = item; } else { this.SourceCollection = itemsControl.ItemsSource ?? itemsControl.Items; } } else { this.SourceItem = (sender as FrameworkElement)?.DataContext; if (this.SourceItem != null) { this.SourceItems = Enumerable.Repeat(this.SourceItem, 1); } this.VisualSourceItem = sourceElement; this.PositionInDraggedItem = sourceElement != null?getPosition(sourceElement) : this.DragStartPosition; } this.SourceItems ??= Enumerable.Empty <object>(); }
/// <summary> /// Initializes a new instance of the DragInfo class. /// </summary> /// /// <param name="sender"> /// The sender of the mouse event that initiated the drag. /// </param> /// /// <param name="e"> /// The mouse event that initiated the drag. /// </param> public DragInfo(object sender, MouseButtonEventArgs e) { this.DragStartPosition = e.GetPosition((IInputElement)sender); this.Effects = DragDropEffects.None; this.MouseButton = e.ChangedButton; this.VisualSource = sender as UIElement; this.DragDropCopyKeyState = DragDrop.GetDragDropCopyKeyState(this.VisualSource); if (sender is ItemsControl) { var itemsControl = (ItemsControl)sender; this.SourceGroup = itemsControl.FindGroup(this.DragStartPosition); this.VisualSourceFlowDirection = itemsControl.GetItemsPanelFlowDirection(); var sourceItem = e.OriginalSource as UIElement; // If we can't cast object as a UIElement it might be a FrameworkContentElement, if so try and use its parent. if (sourceItem == null && e.OriginalSource is FrameworkContentElement) { sourceItem = ((FrameworkContentElement)e.OriginalSource).Parent as UIElement; } UIElement item = null; if (sourceItem != null) { item = itemsControl.GetItemContainer(sourceItem); } if (item == null) { if (DragDrop.GetDragDirectlySelectedOnly(VisualSource)) { item = itemsControl.GetItemContainerAt(e.GetPosition(itemsControl)); } else { item = itemsControl.GetItemContainerAt(e.GetPosition(itemsControl), itemsControl.GetItemsPanelOrientation()); } } if (item != null) { // Remember the relative position of the item being dragged this.PositionInDraggedItem = e.GetPosition(item); var itemParent = ItemsControl.ItemsControlFromItemContainer(item); if (itemParent != null) { this.SourceCollection = itemParent.ItemsSource ?? itemParent.Items; if (itemParent != itemsControl) { var tvItem = item as TreeViewItem; if (tvItem != null) { var tv = tvItem.GetVisualAncestor <TreeView>(); if (tv != null && tv != itemsControl && !tv.IsDragSource()) { return; } } else if (itemsControl.ItemContainerGenerator.IndexFromContainer(itemParent) < 0 && !itemParent.IsDragSource()) { return; } } this.SourceIndex = itemParent.ItemContainerGenerator.IndexFromContainer(item); this.SourceItem = itemParent.ItemContainerGenerator.ItemFromContainer(item); } else { this.SourceIndex = -1; } this.SourceItems = itemsControl.GetSelectedItems(); // Some controls (I'm looking at you TreeView!) haven't updated their // SelectedItem by this point. Check to see if there 1 or less item in // the SourceItems collection, and if so, override the control's // SelectedItems with the clicked item. if (this.SourceItems.Cast <object>().Count() <= 1) { this.SourceItems = Enumerable.Repeat(this.SourceItem, 1); } this.VisualSourceItem = item; } else { this.SourceCollection = itemsControl.ItemsSource ?? itemsControl.Items; } } else { if (sender is UIElement) { this.PositionInDraggedItem = e.GetPosition((UIElement)sender); } } if (this.SourceItems == null) { this.SourceItems = Enumerable.Empty <object>(); } }