/// <summary> /// thx to @osicka from issue #84 /// /// e.g. original source is part of a popup (e.g. ComboBox drop down), the hit test needs to be done on the original source. /// Because the popup is not attached to the visual tree of the sender. /// This function test this by looping back from the original source to the sender and if it didn't end up at the sender stopped the drag. /// </summary> public static bool IsNotPartOfSender(object sender, InputEventArgs e) { var visual = e.OriginalSource as Visual; if (visual == null) { return(false); } var hit = VisualTreeHelper.HitTest(visual, e.GetPosition((IInputElement)visual)); if (hit == null) { return(false); } else { var depObj = e.OriginalSource as DependencyObject; if (depObj == null) { return(false); } var item = VisualTreeHelper.GetParent(depObj.FindVisualTreeRoot()); //var item = VisualTreeHelper.GetParent(e.OriginalSource as DependencyObject); while (item != null && item != sender) { item = VisualTreeHelper.GetParent(item); } return(item != sender); } }
/// <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, InputEventArgs 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>(); } }