WinForm之控件拖动总结(原理篇)

    这几天在公司做项目涉及到了Winform的中涉及到控件项拖动的功能实现,比如TreeView中的项拖动添加到ListView中等。以前没有弄过。然后看了很多例子,还有msdn上面的帮助文档。在这篇文章中总结下。

   本篇主要讲解,两个控件之间项拖动(那么就有一个控件称为源控件,一个称为目标控件)比如将TreeView中的某节点拖动到ListView中。那么源控件是TreeView,目标控件就是ListView。下面将以微软MSDN上的将一个ListBox(ListDragSource)中的项拖动到另一个ListBox(ListDragTarget)中的列子为列讲解这个过程。

下面列出整个过程

(1)设置目标控件ListDragTarget.AllowDrag=true.表面目标控件ListDragTarget可以拖动(其实就是允许该ListDragTarget之外的项进入该控件可以拖动)。

(2)源控件ListDragSource选中某项并拖动,在本例中用到了MouseDown事件(选中某项),MouseMove事件(拖动)。实际上如果控件有ItemDrag事件的话,只需要在ItemDrag一个事件中完成选中和拖动(比如ListView控件就有ItemDrag事件)。在拖动事件中一般是MouseMove或者ItemDrag事件中调用源控件ListDragSource实例的DoDragDrop方法(实际上用目标控件ListDragTarget实例的DoDragDrop方法)。该方法用于传递源控件中的选中项,及拖动效果DragDropEffects,并触发DragDrop事件(这里触发所有DragDrop事件,不分是源控件的DragDrop事件还是目标控件的DragDrop事件)。

(3)注册目标控件ListDragTarget中两个事件DragEnter和DragDrop事件.DragEnter实现拖动的效果,比如 e.Effect = DragDropEffects.Move(这个一定要设置,不光是拖动效果,也涉及到DragDrop事件能否触发的问题,自己实验总结的,不太理解为什么。)。DragDrop实现接受从源控件ListDragSource拖动过来的数据,并将拖动过来的数据添加到该目标控件ListDragTarget中。

上述过程完描述了微软软MSDN上的将一个ListBox(ListDragSource)中的项拖动到另一个ListBox(ListDragTarget)中的列子.如果需要添加鼠标拖动时光标效果还需要用到源控件的ListDragSource.GiveFeedback 事件和目标控件的ListDragTarget.DragOver事件。这里为了以一种最简单的方式展示控件间的拖动过程,所以这里不涉及GiveFeedback和DragOver事件。下面是这两个列子代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WinFormApp
{
    public partial class ListBoxDrgDropListBox : Form
    {
 

        private int indexOfItemUnderMouseToDrag; 
        private Rectangle dragBoxFromMouseDown;
        public ListBoxDrgDropListBox()
        {
            InitializeComponent();
            // ListDragSource
            this.ListDragSource.Items.AddRange(new object[] {"one", "two", "three", "four", 
                                                                "five", "six", "seven", "eight",
                                                                "nine", "ten"});    
            this.ListDragSource.MouseDown+=new MouseEventHandler(ListDragSource_MouseDown);
            this.ListDragSource.MouseMove += new MouseEventHandler(ListDragSource_MouseMove);           
            this.ListDragTarget.AllowDrop = true;
            this.ListDragTarget.DragEnter+=new DragEventHandler(ListDragTarget_DragEnter);
            this.ListDragTarget.DragDrop+=new DragEventHandler(ListDragTarget_DragDrop);     
          
        }     
        //在 MouseDown 事件期间,如果从鼠标位置起鼠标移动的距离大于 SystemInformation.DragSize,则启动拖动动作。
        private void ListDragSource_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 
        {
            //ListBox中Item项的索引
            indexOfItemUnderMouseToDrag = ListDragSource.IndexFromPoint(e.X, e.Y);
            if (indexOfItemUnderMouseToDrag != ListBox.NoMatches) 
            {              
                //记录鼠标按下位置,DragSize获取以鼠标按钮的按下点为中心的矩形的宽度和高度,在该矩形内不会开始拖动操作。
                Size dragSize = SystemInformation.DragSize;
                //创建一个矩形区域(正方形)。以鼠标按下电为中心,以DragSize为高和宽的矩形。
                dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width /2),
                                                               e.Y - (dragSize.Height /2)), dragSize);
            }
            else
               //如果鼠标没有选中ListBox项,则置矩形区域为空
                dragBoxFromMouseDown = Rectangle.Empty;
        }

        private void ListDragSource_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {

            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                //如果鼠标位置在拖动矩形之外(就可以开始拖动了)
                if (dragBoxFromMouseDown != Rectangle.Empty &&
                    !dragBoxFromMouseDown.Contains(e.X, e.Y))
                {
                    //传递ListBox选中项并触发DoDragDrop事件(这里可以是ListDragSoure触发,也可以是ListDragTarget)
                    //DoDragDrop 方法确定当前光标位置下的控件。然后它将检查该控件是否是有效的放置目标。
                    DragDropEffects dropEffect = ListDragSource.DoDragDrop(ListDragSource.Items[indexOfItemUnderMouseToDrag], DragDropEffects.All | DragDropEffects.Link);               
                    if (dropEffect == DragDropEffects.Move)
                    {
                        ListDragSource.Items.RemoveAt(indexOfItemUnderMouseToDrag);                        
                        if (indexOfItemUnderMouseToDrag > 0)
                            ListDragSource.SelectedIndex = indexOfItemUnderMouseToDrag - 1;
                        else if (ListDragSource.Items.Count > 0)                          
                            ListDragSource.SelectedIndex = 0;
                    }
                }
            }
        }

       
        private void ListDragTarget_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            // Ensure that the list item index is contained in the data.
            if (e.Data.GetDataPresent(typeof(System.String)))
            {
                Object item = (object)e.Data.GetData(typeof(System.String));              
                if (e.Effect == DragDropEffects.Copy ||
                    e.Effect == DragDropEffects.Move)
                {
                    ListDragTarget.Items.Add(item);                      

                }
            }
           
        }
        private void ListDragTarget_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {            
            e.Effect = DragDropEffects.Move;
        }
    }
}

 源代码下载

 

 

posted @ 2013-06-01 10:00  焦涛  阅读(4359)  评论(1编辑  收藏  举报