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;
}
}
}
源代码下载