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

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

问题描述

我在 Canvas 上有一个拖放操作,当一个对象被拖入和拖出它时,它应该做一些事情.我的问题是 DragEnter/DragLeave 事件在鼠标移动对象时不断触发,而不仅仅是在进入/退出时.鼠标移动得越快,事件触发的频率就越高.

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.

Canvas DragOver 事件移动了 DragedObject 的 Canvas.Top/Left,我认为这可能是我的问题,但我不确定如何解决这个问题.

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.

推荐答案

以下是事件顺序:

  1. 您的鼠标从您在面板上单击的位置移动.没有事件触发.
  2. 您的鼠标到达面板边缘并进入画布.DragEnter 事件在 Canvas 上触发.
  3. 您的 DragEnter 处理程序移动面板,使其现在位于鼠标下方.由于鼠标不再在 Canvas 上(它在 Panel 上),DragLeave 事件触发.
  4. 您的鼠标进一步移动,再次到达面板边缘.重复第 2 步和第 3 步.
  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.

解决方案是使用自己的代码进行拖放处理,这真的一点都不难.WPF 的命中测试引擎足够强大,可以在当前对象后面进行命中测试,但拖放没有使用此功能.但是,您可以通过使用 VisualTreeHelper.HitTest 重载来直接使用它,该重载采用 HitTestFilterCallbackHitTestResultCallback.只需向它传递一个过滤器,该过滤器会忽略正在拖动的面板中的任何点击.

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.

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

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. 在 MouseDown 上按下左键,记录位置(在 MouseLeave 上擦除位置)
  2. 在使用 {left button down, positionrecorded, current mouse position different by more than delta} 的 MouseMove 上设置一个标志,表示拖动操作正在进行中 &捕捉鼠标
  3. 在进行拖动操作的 MouseMove 上,使用命中测试来确定您的面板应该在哪里(忽略面板本身)并相应地调整其父级和位置.
  4. 在进行拖动操作的 MouseUp 上,释放鼠标捕获并清除正在进行拖动操作"标志

享受吧.

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

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