DragDrop - DragEnter / DragLeave事件保持触发 [英] DragDrop - DragEnter/DragLeave Events keep firing

查看:511
本文介绍了DragDrop - DragEnter / DragLeave事件保持触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Canvas拖放操作,当一个对象被拖入和拖出时,它应该做一些事情。我的问题是,DragEnter / DragLeave事件会随着鼠标移动对象而不会在进入/退出时继续触发。鼠标移动越快,事件就越频繁。



Canvas DragOver事件会移动DraggedObject的Canvas.Top/Left,我认为这可能是我的问题,但我不知道我将如何解决这个问题。

解决方案

这是事件的顺序:


  1. 您的鼠标从您在Panel上点击的鼠标移动。没有事件触发。

  2. 您的鼠标到达面板的边缘并进入画布。 $ DragEnter 事件在Canvas上触发。

  3. 您的 DragEnter 面板现在是在鼠标下面。由于鼠标不再在画布上(它已经在面板上), DragLeave 事件触发。

  4. 您的鼠标进一步移动,再次到达小组的边缘。步骤2和3重复。

移动鼠标的速度越快,您将收到的事件越多。



您的问题的本质是拖放使用命中测试,并通过移动您的面板,您击败了测试的能力,看到背后您的面板知道什么容器被丢弃在



解决方案是使用自己的代码进行拖放处理,这根本不难。 WPF的命中测试引擎足够强大,可以在当前对象后面进行命中测试,但拖放不会使用此功能。您可以直接使用它,通过使用 VisualTreeHelper.HitTest 重载,它需要一个 HitTestFilterCallback 和一个 HitTestResultCallback 。只需传递一个过滤器,忽略被拖动的面板中的任何命中。



我发现,对于像您所描述的场景,通过处理鼠标事件执行拖放操作实际上比使用内置的DoDragDrop更容易,因为您不必处理复杂性(DataObject,DragDropEffects,QueryContinueDrag等)。这种额外的复杂性对于启用应用程序和进程之间拖动的方案非常重要,但不能帮助您执行的操作。



以下是简单的解决方案:


  1. 在MouseDown左下按钮,记录位置(在MouseLeave上删除位置)

  2. 在MouseMove上{左按钮向下,记录位置,当前鼠标位置不同于delta}设置一个标志,表示拖拽操作正在进行&捕获鼠标

  3. 在拖动操作中的MouseMove上,使用命中测试来确定面板的位置(忽略面板本身),并相应调整其父母和位置。

  4. 在拖动操作的MouseUp中,释放鼠标捕获并清除拖动操作正在进行标志

享受。


I have a drag/drop operation on a Canvas that is supposed to do something when an object gets dragged into and out of it. My problem is that the DragEnter/DragLeave events keeps firing as the mouse moves the object over it, not just on enter/exit. The faster the mouse is moving, the more frequently the events fire.

The Canvas DragOver Event moves the Canvas.Top/Left of the DraggedObject and I think that might be my problem, but I am not sure how I would fix this.

解决方案

Here is the sequence of events:

  1. Your mouse moves from where you clicked it across the Panel. No events fire.
  2. Your mouse reaches the edge of the Panel and enters the Canvas. The DragEnter event fires on the Canvas.
  3. Your DragEnter handler moves the Panel so that it is now under the mouse. Since the mouse is no longer over the Canvas (it is over the Panel), the DragLeave event fires.
  4. Your mouse moves further, reaching the edge of the Panel again. Steps 2 and 3 repeat.

The faster you move the mouse, the more events you will receive.

The essence of your problem is that drag-drop uses hit testing, and by moving your panel you are defeating the ability of hit testing to see "behind" your panel to know what container it is being dropped in.

The solution is to use your own code for drag and drop handling, which is really not difficult at all. WPF's hit testing engine is powerful enough to do hit-testing behind the current object but drag-drop doesn't make use of this functionality. You can use it directly however by using the VisualTreeHelper.HitTest overload that takes a HitTestFilterCallback and a HitTestResultCallback. Just pass it a filter that ignores any hits within the panel being dragged.

I've found that for scenarios like you describe, doing drag-drop by handling mouse events is actually easier than using the built in DoDragDrop because you don't have to deal with the complexity (DataObject, DragDropEffects, QueryContinueDrag, etc). This additional complexity is very important for enabling scenarios of dragging between applications and processes, but does not help you for what you are doing.

Here's the simple solution:

  1. On MouseDown with left button down, record the position (on MouseLeave erase the position)
  2. On MouseMove with {left button down, position recorded, current mouse position differs by more than delta} set a flag saying drag operation is in progress & capture the mouse
  3. On MouseMove with drag operation in progress, use hit testing to determine where your panel should be (ignoring the panel itself) and adjust its parenting and position accordingly.
  4. On MouseUp with drag operation in progress, release the mouse capture and clear the "drag operation is in progress" flag

Enjoy.

这篇关于DragDrop - DragEnter / DragLeave事件保持触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆