如何在执行拖动和删除操作时通过控件传递hotTest

时间:2011-11-09 15:07:41

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

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

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

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

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

所有这一切都运行得很好,除了唯一的问题是我无法通过拖放测试来隐藏预览窗口。

2 个答案:

答案 0 :(得分: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顺序为所有窗口调用这些函数,你就完成了。

我希望我可以帮助我的解决方案,但如果有人发现更好的方法,我很有兴趣听到它。

答案 1 :(得分:1)

我对DragDrop事件命中测试提出了类似的问题,我收到的the answer是切换到使用MouseEvents而不是DragDrop事件。我做了转换,从不后悔,也没有尝试过回到WPF的内置DragDrop事件。

作为替代方案,如果您不想使用鼠标事件,则可以在Adorner Layer而不是UI层上显示您的窗口,并且只有在Drop事件发生后才将其呈现为新对象。