DoDragDrop和MouseUp

时间:2008-08-26 23:23:05

标签: .net winforms events drag-and-drop

是否有一种简单的方法可以确保在拖放操作无法完成后,MouseUp事件不会被框架消耗掉并被忽略?

我找到了一篇描述one mechanism的博客文章,但它涉及大量的手工簿记,包括状态标记,MouseMove事件,手动“鼠标离开”检查等等。所有这些我宁愿没有如果可以避免的话,实施。

1 个答案:

答案 0 :(得分:22)

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

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

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

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实际上会触发,因此我们需要确保允许这样做。这是通过检查Mouse位置(使用全局Control.MousePosition属性检索)是否在LabelDrop控件矩形内部来处理的。您还必须确保使用PointToClient将MousePosition转换为相对于客户端窗口的点作为Control.MousePosition返回屏幕相对位置。

因此,通过检查鼠标在而不是并且鼠标按钮现在 up ,我们已经有效地捕获了LabelDrag控件的MouseUp事件! :)现在,您可以在此处执行您想要执行的任何处理,但如果您已经在MouseUp事件处理程序中使用了代码,则效率不高。所以只需从这里调用你的MouseUp事件,传递必要的参数,MouseUp处理程序就不会知道它们的区别。

只是注意,因为我在我的示例中从中调用了DoDragDrop,而中的MouseDown事件处理程序,此代码永远不会实际上触发直接MouseUp事件。我只是把那些代码放在那里,以表明它可以做到。

希望有所帮助!