DoDragDrop 和 MouseUp

Posted

技术标签:

【中文标题】DoDragDrop 和 MouseUp【英文标题】:DoDragDrop and MouseUp 【发布时间】:2010-09-06 22:46:51 【问题描述】:

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

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

【问题讨论】:

啊,我也遇到过这个问题。如果你问我,这很烦人! 【参考方案1】:

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

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

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

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

不过请注意,在我的示例中,当我从 within MouseDown 事件处理程序调用 DoDragDrop 时,此代码应该从不真正获得触发的直接 MouseUp 事件。我只是把那个代码放在那里表明它是可能的。

希望有帮助!

【讨论】:

你的想法很棒,谢谢!但我认为你的 if 语句应该看起来像(按钮可能不是形式,摆脱了虚假不是): if (Control.MouseButtons != MouseButtons.Left && rect.Contains(button.Parent.PointToClient(Control.鼠标位置))) //EXTREMELY IMPORTANT - MUST CALL LabelDrag's DoDragDrop method!! 非常感谢!数小时以来一直试图解决这个问题。 很好的例子,只是想提出一个小建议——将 LabelMain_DragEnter 更改为 LabelDrop_DragEnter。想了一会儿,这涉及到三个标签。

以上是关于DoDragDrop 和 MouseUp的主要内容,如果未能解决你的问题,请参考以下文章

C# winform OnMouseDown里使用DoDragDrop后,OnMouseClick和OnMouseUp被屏蔽了 求大神帮助解决方法

如何捕获取消拖动?

使用鼠标拖放复制文本

WPF拖放自定义类

PictureBox 中的 DragDrop - DragEnter 永远不会被调用

WPF之实现控件内容拖动