玩轉DataGridView之實現兩個GRID間行的拖拽


很多時候我們會有這樣的需求:一個窗體中有兩個GRID,兩個GRID中數據表結構差不多,我們要把一個GRID中的數據加入到另一個GRID中。一般的做法是新增一個導入或導出按鈕,選擇目標行后,通過按鈕來觸發事件,實現兩個GRID中數據的增減。

嘿嘿,但是,如果我們能夠在選中目標行后,直接用鼠標將選中的行拖拽到另一個GRID中是不是比較酷一點呢。

下面,我們就來看看如何實現它。

首先,創建示例數據。

我們還是用上一節:玩轉DataGridView之行的展開與收縮的數據腳本,再用它新建兩張表就行。

select * into Department_A from Department where DparentId=1
select * into Department_B from Department where DparentId=2

 說一下思路:我們要實現的效果是在源Grid中選中行后,按住鼠標左鍵不放,將選中的行從源Grid中拖出,拖入到目標Grid中。其中所作的動作有四個:

1.選中行(可以單行或多行)

2.拖拽行

3.從源Grid中移除選中行(其實也可以不移除,看實際需求了,本例中將行從Grid中移除了)

4.目標Grid中新增選中行。

我們來一一分析。我在項目中建了兩個Grid:sourceGrid即源,targetGrid即目標。

1.選中行

我們必需先要有一個全局變量來保存選中的行。

private DataGridViewSelectedRowCollection sourceRowCollection = null;//用來保存選中的行

給sourceRowCollection賦值當然是在sourceGrid_MouseDown事件中了。這里我們還必需要保證鼠標點擊在有效區域才能給sourceRowCollection賦值。

這里有用到一個類HitTestInfo,NND,不知道微軟為什么這樣命名,害我找了很久。這個類可以獲取當前鼠標所在的RowIndex和ColumnIndex

 private void sourceGrid_MouseDown(object sender, MouseEventArgs e)
        {
            //捕獲鼠標點擊區域的信息
            DataGridView.HitTestInfo hitTestInfo= this.sourceGrid.HitTest(e.X, e.Y);

            if (e.X < 30 && hitTestInfo.RowIndex > -1)
            {
                if (this.sourceGrid.SelectedRows.Count > 0)
                {
                    sourceRowCollection = this.sourceGrid.SelectedRows;
                }
            }
            else
                sourceRowCollection = null;
        }

2.拖拽行

拖拽行就要用到一個很重要的方法:DoDragDrop,它有參數,一個是要拖拽的數據,一個要實現的效果。重要的是調用了后DoDragDrop可以觸發目標控件(本例中是targetGrid)的DragOver、DragDrop等事件。當然前提是你的目標控件的AllowDrop為True。我之前就是因為AllowDrop沒有設置為true,沒有觸發DragOver事件,害我瞎找了好久的原因。

關於DoDragDrop,參考:http://msdn.microsoft.com/zh-cn/library/ie/system.windows.forms.control.dodragdrop.aspx這里更詳細的介紹,也有一個很好的例子。

我們在sourceGrid_MouseMove中去調用DoDragDrop方法:

 private void sourceGrid_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (sourceRowCollection != null)
                {
                    DragDropEffects effect = this.sourceGrid.DoDragDrop(sourceRowCollection, DragDropEffects.Move);
                    if (effect == DragDropEffects.Move)
                    {
                        //在sourceGrid中移除選中行
                        foreach (DataGridViewRow row in sourceRowCollection)
                        {
                            this.sourceGrid.Rows.Remove(row);
                        }
                        //將sourceRowCollection重新置空
                        sourceRowCollection = null;
                    }
                }
            }
        }

注意:effect == DragDropEffects.Move會在目標控件的DragDrop等事件執行完后再執行。
移動到目標窗體時,會觸發targetGrid_DragOver事件,我們在這里設置DragDropEffects的值.

private void targetGrid_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection)))
            {

                e.Effect = DragDropEffects.None;
                return;
            }
            else
            {
                e.Effect = DragDropEffects.Move;  //這個值會返回給DoDragDrop方法
            }
        }

 拖拽完成時,會觸發DragDrop,我們在這里將拖拽的行賦給targetGrid

View Code
 private void targetGrid_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                if (e.Data.GetDataPresent(typeof(DataGridViewSelectedRowCollection)))
                {
                    DataGridViewSelectedRowCollection rowCollection = e.Data.GetData(typeof(DataGridViewSelectedRowCollection)) as DataGridViewSelectedRowCollection;
                    if (rowCollection == null)
                    {
                        return;
                    }
                    //新增行
                    //注意要將鼠標的Point轉換到當前工作區域,否則無法得到正確的HitTestInfo
                    Point p = this.targetGrid.PointToClient(new Point(e.X,e.Y));
                    DataGridView.HitTestInfo hitTestInfo = this.targetGrid.HitTest(p.X, p.Y);
                    //如果鼠標所在的位置的RowIndex>-1,則在當前位置接入列,否則就在最末尾新增列
                    if (hitTestInfo.RowIndex > -1)
                    {
                        this.targetGrid.Rows.Insert(hitTestInfo.RowIndex + 1, rowCollection.Count);
                        for (int i = 0; i < rowCollection.Count; i++)
                        {
                            this.targetGrid.Rows[hitTestInfo.RowIndex + i + 1].Cells["ID"].Value = rowCollection[i].Cells["ToID"].Value;
                            this.targetGrid.Rows[hitTestInfo.RowIndex + i + 1].Cells["DName"].Value = rowCollection[i].Cells["ToDName"].Value;
                            this.targetGrid.Rows[hitTestInfo.RowIndex + i + 1].Cells["Daddress"].Value = rowCollection[i].Cells["ToDaddress"].Value;
                            this.targetGrid.Rows[hitTestInfo.RowIndex + i + 1].Cells["Dtelphone"].Value = rowCollection[i].Cells["ToDtelphone"].Value;
                        }
                    }
                    else
                    {
                        foreach (DataGridViewRow row in rowCollection)
                        {
                            int i = this.targetGrid.Rows.Add();
                            this.targetGrid.Rows[i].Cells["ID"].Value = row.Cells["ToID"].Value;
                            this.targetGrid.Rows[i].Cells["DName"].Value = row.Cells["ToDName"].Value;
                            this.targetGrid.Rows[i].Cells["Daddress"].Value = row.Cells["ToDaddress"].Value;
                            this.targetGrid.Rows[i].Cells["Dtelphone"].Value = row.Cells["ToDtelphone"].Value;
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

3.從源Grid中移除選中行

移除選中行已經在sourceGrid_MouseMove事件中了,即:

if (effect == DragDropEffects.Move)
                    {
                        //在sourceGrid中移除選中行
                        foreach (DataGridViewRow row in sourceRowCollection)
                        {
                            this.sourceGrid.Rows.Remove(row);
                        }
                        //將sourceRowCollection重新置空
                        sourceRowCollection = null;
                    }

4.目標Grid中新增選中行

新增行的代碼也在targetGrid_DragDrop中,因為這個在拖拽完成時觸發。這里我們分新增與插入的情況,詳見上面的代碼。

 

最后說明一下,我只做了界面上的兩個GRID中數據的增減,並沒有將更改保存到數據庫中,大家有興趣的可以自己去實現一下。

PS:貌似同一個窗體中的兩個GRID不能有相同的列名,這點微軟的做法讓我很不爽,綁定數據的時候我不得不多寫一個方法。

 源代碼:DataGridDemo,拖拽窗體即項目中的MoveGridForm


免責聲明!

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



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