19

有没有一种简单的方法可以确保在拖放失败后,MouseUp 事件不会被框架吃掉和忽略?

我找到了一篇描述一种机制的博客文章,但它涉及大量手动记账,包括状态标志、MouseMove 事件、手动“鼠标离开”检查等。如果可以的话,我宁愿不必实现所有这些避免。

4

1 回答 1

24

我最近想在我的项目中加入拖放功能,但我没有遇到过这个问题,但我很感兴趣,真的很想看看我是否能想出比你链接的页面中描述的方法更好的方法到。我希望我清楚地理解了你想做的一切,总的来说,我认为我成功地以一种更优雅、更简单的方式解决了这个问题。

顺便说一句,对于像这样的问题,如果您提供一些代码会很棒,这样我们就可以准确地看到您正在尝试做什么。我这么说只是因为我在我的解决方案中假设了一些关于您的代码的事情......所以希望它非常接近。

这是代码,我将在下面解释:

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 处理程序将永远不会知道其中的区别。

不过请注意,在我的示例中,当我从 MouseDown 事件处理程序中调用 DoDragDrop 时此代码实际上永远不会触发直接的 MouseUp 事件。我只是把代码放在那里以表明它是可能的。

希望有帮助!

于 2008-08-27T14:00:12.353 回答