IsMouseOver 和 DragLeave 无法正常工作

IsMouseOver and DragLeave not working properly

我的 UI 上有一个 grid/panel 可以执行放下操作。该控件是一个网格,其中包含一些动态创建的内容(如果重要,则包含一个包含边框堆栈面板的视图框)。

当我将相关信息拖到网格中时,我希望它更改(重新生成)内部内容,当它掉落或离开时,它应该恢复正常。我的 'change it' 和 'put it back' 方法工作得很好,但我无法确定何时调用它们。

我在网格上有拖动进入和拖动离开事件。进入效果很好,但离开效果不好。一旦鼠标越过网格内内容的顶部,它就会触发拖动离开事件,因此它会更改内容(如果这将其放回子内容之外,它会再次触发拖动输入并闪烁) .

我的第一个想法是确定鼠标是否实际上仍在网格上,然后在不放回内容的情况下直接退出。但是,这似乎不起作用。这是我的拖放代码:

        private void Grid_DragLeave(object sender, DragEventArgs e)
    {
        var wizard = DataContext as WizardVM;
        var gd = sender as Grid;

        if (wizard == null || gd == null || gd.IsMouseOver ||
            gd.Children.Cast<FrameworkElement>().Any(x => x.IsMouseOver)) return;

        wizard.Assembly.CollapsePreview();
    }

如您所见,我什至尝试迭代网格的子项,看看鼠标悬停在其中任何一个上是否为 true 并放弃,但它仍然只是为所有这些返回 false 并崩溃。我认为 IsMouseOver 应该告诉我鼠标是否完全结束,即使它是控件的子项...

好的,经过更多研究后,我发现了一些似乎有效的方法。我最终不得不使用 VisualTreeHelper.HitTest 并使用具有回调的重载并获取所有命中项,即使它被遮盖了。这是我的最终代码:

    void Grid_DragLeave(object sender, DragEventArgs e)
    {
        var wizard = DataContext as WizardVM;
        var gd = sender as Grid;

        if (wizard == null || gd == null) return;
        Point pt = e.GetPosition(this);
        hitResults.Clear();
        VisualTreeHelper.HitTest(gd, null, GridHitTestResultCallback,
            new PointHitTestParameters(pt));

        if (!hitResults.Contains(gd))
        {
            wizard.Assembly.IsExpanded = false;
        }
    }

    HitTestResultBehavior GridHitTestResultCallback(HitTestResult result)
    {
        hitResults.Add(result.VisualHit);
        return HitTestResultBehavior.Continue;
    }

基本上它获取与完整 window 相关的点,然后使用该点和我尝试使用的整体网格调用 HitTest。回调填充命中测试命中的视觉对象列表。最后,原始方法检查网格是否在命中列表中,如果不在,则将其折叠。

作为旁注,出于不相关的原因,我还从 .ExpandPreview() 和 .CollapsePreview() 方法更改为 .IsExpanded 属性 ...不想让任何人对这种变化感到困惑。 ..