关于.net:DoDragDrop和MouseUp

关于.net:DoDragDrop和MouseUp

DoDragDrop and MouseUp

是否有一种简单的方法来确保拖放失败后,框架不会吞噬MouseUp事件并忽略该事件?

我发现了一篇博客文章,描述了一种机制,但是它涉及大量的手动记账,包括状态标志,MouseMove事件,手动"鼠标离开"检查等。可以避免。


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

快速说明一下,对于这样的问题,如果您提供一些代码,那将非常好,这样我们就可以准确地看到您要执行的操作。我之所以这么说是因为我在解决方案中假设了一些有关您代码的信息...所以希望它已经很接近了。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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控件矩形的内部来进行处理。您还必须确保将MousePosition转换为相对于以PointToClient为控件的客户端窗口的点.MousePosition返回屏幕的相对位置。

因此,通过检查鼠标不在放置控件上并且鼠标按钮现在位于上方,我们已经有效地捕获了LabelDrag控件的MouseUp事件! :)现在,您可以执行此处要执行的任何处理,但是如果您已经拥有在MouseUp事件处理程序中使用的代码,则效率不高。因此,只需从此处调用MouseUp事件,并向其传递必要的参数,MouseUp处理程序将永远不会知道它们之间的区别。

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

希望有帮助!


推荐阅读