zoukankan      html  css  js  c++  java
  • 玩转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

  • 相关阅读:
    magento 去掉index.php
    TCP三次握手与四次挥手
    <Jper和Iperf>的安装及使用
    【Python】安装方法小结
    【ubuntu】日常网络配置信息的查看及修改
    DNS解析
    【Dig工具】
    【ping/tracert】的简单使用
    【VMvare】yum在线源
    配置文件加载
  • 原文地址:https://www.cnblogs.com/Gyoung/p/2486002.html
Copyright © 2011-2022 走看看