這幾天在公司做項目涉及到了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; } } }