如何在执行拖放操作时通过控件传递 hitTest

发布于 2024-12-14 09:29:53 字数 1288 浏览 2 评论 0原文

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

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;
}

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

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

除了我无法隐藏预览窗口以进行拖放点击测试之外,所有这些都工作得很好。

I have a tab control which allows me to drag the tab items out of my application.
This dragging will open a new window which will follow the mouse until I release the left mouse button.
Also it is possible to drag the tab item back into the source tab control and reattach it to its former parent or to any other control capable of understanding the dragged data.

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();
   }
}

The problem I am having now is that when the preview window is following the mouse it is positioned directly under the cursor.
This way the dragEnter and dragOver events of the source tab control are not firing since the window is blocking the hit testing.
Even if I set IsHitTestVisible to false in the window the hit test will be blocked while the drag&drop is still active.
Setting IsEnabled to false and changing the background to null does not have any effect.

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

Is there any possibility to hide the preview window from any hit tests or to pass the hit test manually to any control visually behind the dragged window?

Edit, some more information to my problem:
I don't only want to drag tab items out of my tab control and open new windows for them, but also I want to be able to drag additional tab items into existing drag-out-windows.
Additionally dragging a tab item back into the original tab control should be possible.

All of this is working quite well except for the only problem that I can't hide the preview window from drag&drop-hittesting.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

满身野味 2024-12-21 09:29:53

我对 DragDrop 事件命中测试有类似的问题,并且 我收到的答案是改用 MouseEvents 而不是 DragDrop事件。我做出了这种转变并且从未后悔过,也从未尝试过回到 WPF 的内置 DragDrop 事件。

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

I had a similar question about DragDrop event hit testing, and the answer I received was to switch to using MouseEvents instead of DragDrop events. I made the switch and never regretted it, nor have I ever tried going back to WPF's built-in DragDrop events.

As an alternative if you don't want to use use Mouse Events, would be to show your window on the Adorner Layer instead of the UI layer, and only render it as a new object once the Drop event occurs.

鸩远一方 2024-12-21 09:29:53

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 顺序为所有窗口调用该函数,然后就完成了。

我希望我可以帮助解决我的解决方案,但如果有人发现更好的方法来做到这一点,我非常有兴趣听到它。

The answer of Rachel is absolutely correct and I would recommend to anyone to use the the normal MouseEvents instead of the DragDropEvents.
But since I have several windows in my application involved into the drag I had to come up with a different solution:

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);
        }
    }

where DragOver(hitControl, _draggedItem) is the function which is normally called when the DragEnter or DragOver event fires and GetCursorPos() is a Win32 call to get the correct mouse position.

Now you have to call that functions for all windows in the correct z-order and you are done.

I hope i could help with my solution, but if anyone spots a better way to do this I am very interested to hear about it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文