代码之家  ›  专栏  ›  技术社区  ›  Chris Ammerman

DoDragDrop和MouseUp

  •  20
  • Chris Ammerman  · 技术社区  · 17 年前

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

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

    1 回复  |  直到 17 年前
        1
  •  25
  •   Leon Bambrick jon Z    9 年前

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

    顺便说一句,对于这样的问题,如果你提供一些代码,这样我们就能准确地看到你想做什么,那就太好了。我这么说只是因为我在解决方案中假设了一些关于你的代码的事情。…所以希望它非常接近。

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

    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转换为相对于客户端窗口的点。MousePosition返回一个 屏幕相对 位置。

    因此,通过检查鼠标是否 在拖放控件上,鼠标按钮现在 向上的 我们有效地捕获了LabelDrag控件的MouseUp事件!:)现在,你可以在这里做任何你想做的处理,但如果你已经有了在MouseUp事件处理程序中使用的代码,这是低效的。因此,只需从这里调用MouseUp事件,并向其传递必要的参数,MouseUp处理程序就永远不会知道其中的区别。

    不过,这只是一个注释,我称之为DoDragDrop 在内部 在我的例子中,MouseDown事件处理程序,这段代码应该 从不 实际上,直接触发MouseUp事件。我只是把代码放在那里,以表明这是可能的。

    希望这能有所帮助!

    推荐文章