在WPF中的网格中的单元格之间拖放自定义控件

我有一些自定义控件,可以动态添加到自定义网格中。 这些控件可以跨越多个列和行(大小都相同)。 我想在行和列之间拖放。 我可以拖动单个控件,但它们可以无限制地移动到任何地方。 即使是离网。 我想这样做,所以它只能在网格内拖动并捕捉到它拖动到的列/行。

有没有简单的方法来做到这一点?

老实说,如果我能得到它已经结束的当前行/列,那么我需要做的就是将它的列/行设置为它们并且可能会这样做然后只是担心将它保留在网格中。

我想出了一个很好玩的方式!

我计算出MouseUp事件上鼠标所在的网格上的位置,然后是鼠标在控件上的相对位置,因为它跨越了几行/列。

public void getPosition(UIElement element, out int col, out int row) { DControl control = parent as DControl; var point = Mouse.GetPosition(element); row = 0; col = 0; double accumulatedHeight = 0.0; double accumulatedWidth = 0.0; // calc row mouse was over foreach (var rowDefinition in control.RowDefinitions) { accumulatedHeight += rowDefinition.ActualHeight; if (accumulatedHeight >= point.Y) break; row++; } // calc col mouse was over foreach (var columnDefinition in control.ColumnDefinitions) { accumulatedWidth += columnDefinition.ActualWidth; if (accumulatedWidth >= point.X) break; col++; } } 

然后我从正常位置拿走相对位置,这样当你放下它时,它总是落在屏幕的左上角。 当我移动我的控件时,我使用边距来移动它,这会在当时拧紧网格上的位置,如下所示:

 void Chart_PreviewMouseMove(object sender, MouseEventArgs e) { if (IsMouseCaptured) { Point mouseDelta = Mouse.GetPosition(this); mouseDelta.Offset(-mouseOffset.X, -mouseOffset.Y); Margin = new Thickness( Margin.Left + mouseDelta.X, Margin.Top + mouseDelta.Y, Margin.Right - mouseDelta.X, Margin.Bottom - mouseDelta.Y); } } void Chart_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mouseOffset = Mouse.GetPosition(this); CaptureMouse(); parent.currentObject = this; } 

要解决这个问题,我只需重置保证金。

 public void updatePosition() { Grid.SetRow(this, (int)position.Y); Grid.SetColumn(this, (int)position.X); Margin = new Thickness(); } 

我希望这可以帮助别人,因为找到答案让我感到非常沮丧,最后我设法得到了很多关于如何做事的小片段,最终想出了我自己的解决方案。

有没有简单的方法来做到这一点?

我会说这个问题的答案在很大程度上取决于你使用拖放function的经验……对于一个初学者,我会说答案是否定的,但对于有经验和一些常识的人来说,这可能不会太糟糕。

要确定用户鼠标所在的Grid单元格不是直接的。 您可以处理PreviewDragOver事件并使用VisualTreeHelper.HitTest方法检查鼠标当前所在的控件:

 private void PreviewDragOver(object sender, DragEventArgs e) { HitTestResult hitTestResult = VisualTreeHelper.HitTest(adornedUIElement, e.GetPosition(adornedUIElement)); Control controlUnderMouse = hitTestResult.VisualHit.GetParentOfType(); } 

GetParentOfType方法是我创建的一个有用的扩展方法,但您可以很容易地将它转换为普通方法:

 public static T GetParentOfType(this DependencyObject element) where T : DependencyObject { Type type = typeof(T); if (element == null) return null; DependencyObject parent = VisualTreeHelper.GetParent(element); if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) parent = ((FrameworkElement)element).Parent; if (parent == null) return null; else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) return parent as T; return GetParentOfType(parent); } 

当然,一旦你的controlUnderMouse变量中有一个Control ,你仍然需要做一些相当大的工作,因为你在UIElement工作直到你到达Grid …你当然可以进一步使用GetParentOfType方法使您的工作更轻松。