【问题标题】:How to pass the hitTest through a control while performing a drag&drop operation如何在执行拖放操作时通过控件传递 hitTest
【发布时间】:2011-11-09 15:07:40
【问题描述】:

我有一个选项卡控件,它允许我将选项卡项拖出我的应用程序。
此拖动将打开一个新窗口,该窗口将跟随鼠标,直到我释放鼠标左键。
也可以将选项卡项拖回源选项卡控件并将其重新附加到其前父级或任何其他能够理解拖动数据的控件。

private static void DragOutTabControl_PreviewQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
   e.Handled = true;

   if (DragControlIsHit)
   {
      if (_previewWindow != null && _previewWindow.IsVisible)
      {
         _previewWindow.Clear();
         _previewWindow.Hide();
      }
   }
   else
   {
      if (_previewWindow == null)
      {
         _previewWindow = new PreviewWindow();
         _previewWindow.SetData();
      }

      _previewWindow.Left = CursorPos.X - 15;
      _previewWindow.Top = CursorPos.Y - 15;
      _previewWindow.Show();
   }
}

我现在遇到的问题是,当预览窗口跟随鼠标时,它直接位于光标下方。
这样,源选项卡控件的 dragEnter 和 dragOver 事件不会触发,因为窗口阻止了命中测试。
即使我在窗口中将 IsHitTestVisible 设置为 false,当拖放仍然处于活动状态时,命中测试也会被阻止。
将 IsEnabled 设置为 false 并将背景更改为 null 没有任何效果。

public PreviewWindow()
{
   Background = null;
   IsEnabled = false;
   IsHitTestVisible = false;
}

是否有可能从任何命中测试中隐藏预览窗口或手动将命中测试传递给拖动窗口后面的任何控件?

编辑,我的问题的更多信息:
我不仅希望将选项卡项从选项卡控件中拖出并为它们打开新窗口,而且我还希望能够将其他选项卡项拖动到现有的拖出窗口中。
此外,应该可以将选项卡项拖回原始选项卡控件。

所有这些都运行良好,唯一的问题是我无法从拖放测试中隐藏预览窗口。

【问题讨论】:

    标签: c# wpf drag-and-drop hittest


    【解决方案1】:

    我有一个关于DragDrop 事件命中测试的类似问题,我收到的the answer 是切换到使用MouseEvents 而不是DragDrop 事件。我进行了切换并且从未后悔过,也从未尝试过返回 WPF 的内置 DragDrop 事件。

    如果您不想使用鼠标事件,另一种方法是在 Adorner 层而不是 UI 层上显示您的窗口,并且仅在 Drop 事件发生时将其呈现为新对象。

    【讨论】:

    • 首先感谢您的回答。它支持我自己对该主题的想法,但由于我必须能够处理来自其他来源的拖放,我不想使用普通的 MouseEvents 而不是 DragDropEvents。
    • 我也尝试了装饰器,但我不喜欢在释放鼠标按钮时必须创建窗口。
    【解决方案2】:

    Rachel 的回答是绝对正确的,我建议任何人使用普通的 MouseEvents 而不是 DragDropEvents。
    但由于我的应用程序中有几个窗口涉及到拖动,我不得不想出一个不同的解决方案:

    private static void ProcessDraggedHitTest(
            Window window)
        {
            var CursorPos = GetCursorPos();
            var MousePosition = Mouse.GetPosition(window);
    
            IDragTarget hitControl = null;
            var hitTestResult = VisualTreeHelper.HitTest(window, new Point(CursorPos.X + MousePosition.X, CursorPos.Y + MousePosition.Y));
            if (hitTestResult != null)
            {
                var parent = hitTestResult.VisualHit as DependencyObject;
                while (parent != null)
                {
                    hitControl = parent as IDragTarget;
                    if (tileOutControl != null)
                        break;
                    else
                        parent = VisualTreeHelper.GetParent(parent);
                }
    
                if (hitControl != null)
                    DragOver(hitControl, _draggedItem);
            }
        }
    

    其中 DragOver(hitControl, _draggedItem) 是在 DragEnter 或 DragOver 事件触发时通常调用的函数,GetCursorPos() 是 Win32 调用以获取正确的鼠标位置。

    现在您必须以正确的 z 顺序为所有窗口调用该函数,然后您就完成了。

    我希望我能帮助解决我的问题,但如果有人发现了更好的方法,我很想听听。

    【讨论】:

      猜你喜欢
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多