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;
        }
    }
}

 源代碼下載

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM