DoDragDrop 和 MouseUp
-
09-06-2019 - |
题
有没有一种简单的方法可以确保拖放无法完成后,MouseUp 事件不会被框架耗尽并忽略?
我发现一篇博客文章描述了 一种机制, ,但它涉及大量的手动簿记,包括状态标志、MouseMove 事件、手动“鼠标离开”检查等。如果可以避免的话,我宁愿不必实施所有这些。
解决方案
我最近想在我的项目中添加拖放功能,但我没有遇到这个问题,但我很感兴趣,并且真的想看看我是否可以想出一种比您链接的页面中描述的方法更好的方法到。我希望我清楚地理解你想做的一切,总的来说,我认为我成功地以更加优雅和简单的方式解决了问题。
顺便说一句,对于这样的问题,如果您提供一些代码,那就太好了,这样我们就可以准确地看到您正在尝试做什么。我这么说只是因为我在我的解决方案中假设了一些关于您的代码的事情......所以希望它非常接近。
这是代码,我将在下面解释:
this.LabelDrag.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.LabelDrag_QueryContinueDrag);
this.LabelDrag.MouseDown += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseDown);
this.LabelDrag.MouseUp += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseUp);
this.LabelDrop.DragDrop += new System.Windows.Forms.DragEventHandler(this.LabelDrop_DragDrop);
this.LabelDrop.DragEnter += new System.Windows.Forms.DragEventHandler(this.LabelMain_DragEnter);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void LabelDrop_DragDrop(object sender, DragEventArgs e)
{
LabelDrop.Text = e.Data.GetData(DataFormats.Text).ToString();
}
private void LabelMain_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
private void LabelDrag_MouseDown(object sender, MouseEventArgs e)
{
//EXTREMELY IMPORTANT - MUST CALL LabelDrag's DoDragDrop method!!
//Calling the Form's DoDragDrop WILL NOT allow QueryContinueDrag to fire!
((Label)sender).DoDragDrop(TextMain.Text, DragDropEffects.Copy);
}
private void LabelDrag_MouseUp(object sender, MouseEventArgs e)
{
LabelDrop.Text = "LabelDrag_MouseUp";
}
private void LabelDrag_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
//Get rect of LabelDrop
Rectangle rect = new Rectangle(LabelDrop.Location, new Size(LabelDrop.Width, LabelDrop.Height));
//If the left mouse button is up and the mouse is not currently over LabelDrop
if (Control.MouseButtons != MouseButtons.Left && !rect.Contains(PointToClient(Control.MousePosition)))
{
//Cancel the DragDrop Action
e.Action = DragAction.Cancel;
//Manually fire the MouseUp event
LabelDrag_MouseUp(sender, new MouseEventArgs(Control.MouseButtons, 0, Control.MousePosition.X, Control.MousePosition.Y, 0));
}
}
}
我省略了大部分设计器代码,但包含了事件处理程序链接代码,以便您可以确定什么链接到什么。在我的示例中,拖/放发生在标签 LabelDrag 和 LabelDrop 之间。
我的解决方案的主要部分是使用 QueryContinueDrag 事件。在该控件上调用 DoDragDrop 后,当键盘或鼠标状态发生更改时,将触发此事件。您可能已经这样做了,但是调用源控件的 DoDragDrop 方法而不是与窗体关联的方法非常重要。否则 QueryContinueDrag 将不会触发!
需要注意的一件事是,当您释放鼠标时,QueryContinueDrag 实际上会触发 在下降控件上 所以我们需要确保我们允许这一点。这是通过检查鼠标位置(使用全局 Control.MousePosition 属性检索)是否位于 LabelDrop 控件矩形内部来处理的。您还必须确保使用 PointToClient 将 MousePosition 转换为相对于客户端窗口的点,因为 Control.MousePosition 返回一个 屏幕相关 位置。
因此,通过检查鼠标是否 不是 放在拖放控件上并且鼠标按钮现在位于 向上 我们已经有效地捕获了 LabelDrag 控件的 MouseUp 事件!:) 现在,您可以在此处执行您想要执行的任何处理,但如果您已经有在 MouseUp 事件处理程序中使用的代码,则效率不高。因此,只需从此处调用 MouseUp 事件,并向其传递必要的参数,MouseUp 处理程序将永远不会知道其中的差异。
请注意,因为我从以下位置调用 DoDragDrop 之内 在我的示例中,MouseDown 事件处理程序,此代码应该 绝不 实际上直接触发 MouseUp 事件。我只是将该代码放在那里以表明可以做到这一点。
希望有帮助!