很多时候我们会有这样的需求:一个窗体中有两个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;}}elsesourceRowCollection = 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转换到当前工作区域,否则无法得到正确的HitTestInfoPoint 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

玩转DataGridView之实现两个GRID间行的拖拽相关推荐

  1. panda 透视表 计算比例_用案例教你玩Excel-《第2例:给领导汇报考评结果-拖拽的透视表》...

    本系列文章旨在完全用实战案例来分享excel在世界级企业中的应用,绝不让你零零散散学知识,不光让你提高效率,还切实提高你的影响力,你要全掌握了,保证你脱颖而出.尤其适合在企业中工作的.中度.重度依赖e ...

  2. 使用一条带箭头的虚线连接两个div,并且div拖拽时保持虚线连接

    1.如何使用带箭头的虚线将div连接 a.了解path命令 我们可以使用svg的path配合marker属性来实现,首先我们需要了解path元素的命令 M(x,y) 起始位置的坐标 L(x,y) 结束 ...

  3. iPhone手机进阶玩法, 轻敲两下,即可截屏

    iPhone手机进阶玩法, 轻敲两下,即可截屏.

  4. winform代码:关联窗体数据更新,删除dataGridview中选中的一行或多行

    一.关联窗体数据更新 关联窗体数据修改时,如果一个为总体数据显示窗体A,另一个为详细修改窗体B,从A进入B,在B中对数据进行修改,然后返回A,这时A窗体的数据需要更新. 我采用最简单的方法,首先保证每 ...

  5. 两条线段相切弧_两条直线间的圆弧连接

    教学重点 两条直线间圆弧连接的步骤. 教学难点 如何确定连接圆弧的圆心. 学情分析 1 .对"圆弧连接"定义里 "光滑连接"的理解有些模糊. 2 .对作图时要求 ...

  6. win8 metro 拖拽重排grid

    0.1 http://1.metrowin8.sinaapp.com/Code/index.html 拖拽重排实现思路  : 1.初始化拖拽对象时,上传拖拽对象中心点信息(包括id,className ...

  7. ACMNO.25 C语言-间隔输出 写一函数,输入一个四位数字,要求输出这四个数字字符,但每两个数字间空格。如输入1990,应输出1 9 9 0。 输入 一个四位数 输出 增加空格输出

    题目描述 写一函数,输入一个四位数字,要求输出这四个数字字符,但每两个数字间空格.如输入1990,应输出"1 9 9 0". 输入 一个四位数 输出 增加空格输出 样例输入 199 ...

  8. R语言dplyr包使用bind_rows函数纵向合并两个dataframe(行生长)、使用bind_cols函数横向合并两个dataframe(列生长)

    R语言dplyr包使用bind_rows函数纵向合并两个dataframe(行生长).使用bind_cols函数横向合并两个dataframe(列生长) 目录

  9. 【IT笔试面试题整理】 二叉树任意两个节点间最大距离

    求一个二叉树中任意两个节点间的最大距离,两个节点的距离的定义是这两个节点间边的个数, 比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度. 一种是:经过根节点,此时只 ...

  10. SQL server 两台服务器间连接查询

    --两台服务器间连接查询: --建立连接: sp_addlinkedserver hs sp_addlinkedserver hs1 EXEC sp_addlinkedsrvlogin 'hs', ' ...

最新文章

  1. linux apache配置目录大小写,linux apache 配置URL地址栏大小写不敏感配置
  2. gearman php 进程守护,用 Gearman 分发 PHP 应用程序的工作负载
  3. 一步一步搭建ELK日志处理集群(自己做过测试)
  4. Yii查看SQL语句:getRawSql()
  5. pcb成型板aoi检测_通过自动光学检测(AOI)实现PCB高速检测
  6. Vue父组件向子组件传值
  7. MySql视图、存储过程、函数、索引
  8. printf 格式化最常用用法
  9. # 研究杂感 × VOSviewer(第三辑)
  10. win7 梦幻桌面下载地址
  11. 双摄像头做slsm_刚刚考完!真实双机位复试经验帮你避雷!
  12. 如何复制权限受限PDF文件的内容(亲测有效,Microsoft Edge打开pdf文件)
  13. 正味集团冲刺港股:年营收3.4亿杨声耀夫妇控制64%股权
  14. 【驱动调试】SoftICE 使用说明
  15. 实现线程同步的几种方法
  16. 【STM32】DAC详解
  17. 常用的Linux快捷键 [译]
  18. numpy创建空数组
  19. Mininet-WIFI(一) Mininet学习笔记之基本操作
  20. 网站外链建设入门指南

热门文章

  1. childNodes.length 的临时保存
  2. Vue 读取Excel数据
  3. 防止xss(脚本攻击)的方法之过滤器
  4. ndoejs后台查询数据库返回的值-进行解析
  5. 无限分级函数 简单 引用绑值
  6. UVA 299 - Train Swapping(冒泡排序)
  7. 简单的 socket 代码
  8. 【Windows socket+IP+UDP+TCP】网络基础
  9. Android内存泄漏分析实战
  10. android音量知识总结