这几天在公司做项目涉及到了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; } } }