我在 form_MouseDown 事件上有一个 Drag() 方法。我在表单上也有一个点击事件。问题是,如果我点击表单,MouseDown 事件会被触发,它永远不会有机会触发点击事件。
解决此问题的最佳方法是什么?如果表单实际上被拖动,我正在考虑计算像素,但必须有更好的方法。有什么建议么?
我找到了这个解决方案,虽然它是针对双击和鼠标按下事件:
void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && e.Clicks ==1)
{
PictureBox pb = (PictureBox)sender;
DoDragDrop((ImageData)pb.Tag, DragDropEffects.Copy);
}
}
来源:http ://code.rawlinson.us/2007/04/c-dragdrop-and-doubleclick.html
如果表单实际上被拖动,我正在考虑计算像素,但必须有更好的方法。
不,这正是你必须这样做的方式。
这不仅仅是软件限制;它也非常实用。如果您从用户的角度考虑问题,您将立即看到问题以及解决方案。问问自己,点击和拖动有什么区别?
它们都以鼠标按钮在对象上向下移动开始,但其中一个以鼠标按钮在相同位置的对象上返回结束,而另一个以鼠标按钮在完全不同的位置返回结束.
由于时间机器尚未完善,因此您无法提前知道这一点。
所以是的,您需要保持某种距离阈值,如果指针在对象上方向下移动时超出该距离阈值,那么您认为它是一种阻力。否则,您认为这是一次点击。
该距离阈值不应为 0。不应要求用户完全保持鼠标不动以启动点击。很多用户都是低于标准的鼠标。尝试点击时,它们很可能会轻微抽搐。如果阈值为 0,则他们在尝试单击时最终会进行大量无意的拖动。
当然,您实际上不必担心任何这些或自己计算阻力阈值。相反,使用 Windows 默认值,可通过调用GetSystemMetrics
函数并指定SM_CXDRAG
或来获得SM_CYDRAG
。(这些可能会在 WinForms 框架的某个地方公开,但我不这么认为。自己 P/Invoke 它们同样容易。)
const int SM_CXDRAG = 68;
const int SM_CYDRAG = 69;
[DllImport("user32.dll")]
static extern int GetSystemMetrics(int index);
Point GetDragThreshold()
{
return new Point(GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
}
在 UX/UI 领域,这类事情被称为滞后或去抖动,类似于在物理学和电子学中使用这些术语。
不幸的是,在“按下按钮”时,您还不知道所需的操作是单击还是拖放。你稍后会发现它。
对于点击,决定因素是“没有移动”和“按钮向上”。
对于拖动,决定因素是“运动”和“按钮向上”。
因此,要消除这些交互的歧义,您不仅要跟踪按钮,还要跟踪移动。您不需要跟踪整体运动,只有 button-down 和 button-up 之间的运动是有趣的。
因此,这些事件是启动/停止 Mouse.Capture 机制(动态呈现拖动装饰器和放置位置提示)的好地方,或者以更简单的形式 - 存储移动矢量的原点和目标并检查距离是否 > D(即使发生了移动,也应该有一些安全的最小距离,在该距离内取消 DRAG。鼠标有时是“锯齿状的”,人们真的不喜欢你的应用程序在结束时双击开始拖动快速鼠标指针移动:) )