DataGridView之行的展开与收缩
很多数据都有父节点与子节点,我们希望单击父节点的时候可以展开父节点下的子节点数据。
比如一个医院科室表,有父科室与子科室,点击父科室后,在父科室下面可以展现该科室下的所有子科室。
我们来说一下在DataGridView中如何实现这个功能。
首先,创建示例数据:

- create table Department
- (
- ID int identity(1,1) not null,
- DName varchar(20) null,
- DparentId int null,
- Dtelphone varchar(20) null,
- Dhospital varchar(50) null
- )
- insert into Department values('门诊外室',1,'','XXX医院')
- insert into Department values('门诊内科',1,'','XXX医院')
- insert into Department values('门诊手术',1,'','XXX医院')
- insert into Department values('门诊儿科',1,'','XXX医院')
- insert into Department values('神经内室',2,'','XXX医院')
- insert into Department values('神经外科',2,'','XXX医院')
- insert into Department values('住院手术',2,'','XXX医院')
- insert into Department values('住院康复',2,'','XXX医院')

其实思路很简单,就是在展开父节点的时候,在父节点下插入新的DataGridViewRow;收缩父节点的时候,在父节点下删除该子节点的DataGridViewRow。
为了简便,代码中的数据读取我都直接硬编码了。
加载父节点数据,除了数据库中的列外我还新加了两列:IsEx与EX。

- private void DataGridBing(DataTable table)
- {
- if (table.Rows.Count > )
- {
- for (int i = ; i < table.Rows.Count; i++)
- {
- int k = this.dataGridView1.Rows.Add();
- DataGridViewRow row = this.dataGridView1.Rows[k];
- row.Cells["ID"].Value = table.Rows[i]["ID"];
- row.Cells["DName"].Value = table.Rows[i]["DName"];
- row.Cells["Daddress"].Value = table.Rows[i]["Daddress"];
- row.Cells["Dtelphone"].Value = table.Rows[i]["Dtelphone"];
- //用于显示该行是否已经展开
- row.Cells["IsEx"].Value = "false";
- //用于显示展开或收缩符号,为了简单我就直接用字符串了,其实用图片比较美观
- row.Cells["EX"].Value = "+";
- }
- }
- }

下面就是Cell的单击事件了,分别在事件中写展开的插入与收缩的删除.
插入子节点:

- string isEx=this.dataGridView1.Rows[e.RowIndex].Cells["IsEx"].Value.ToString();
- if (this.dataGridView1.Columns[e.ColumnIndex].Name == "EX" && isEx=="false")
- {
- string id = this.dataGridView1.Rows[e.RowIndex].Cells["ID"].Value.ToString();
- DataTable table = GetDataTable("select * from Department where DparentId="+id);
- if (table.Rows.Count > )
- {
- //插入行
- this.dataGridView1.Rows.Insert(e.RowIndex+, table.Rows.Count);
- for (int i = ; i < table.Rows.Count; i++)
- {
- DataGridViewRow row = this.dataGridView1.Rows[e.RowIndex + i+];
- row.DefaultCellStyle.BackColor = Color.CadetBlue;
- row.Cells["ID"].Value = table.Rows[i]["ID"];
- row.Cells["DName"].Value = table.Rows[i]["DName"];
- row.Cells["Daddress"].Value = table.Rows[i]["Daddress"];
- row.Cells["Dtelphone"].Value = table.Rows[i]["Dtelphone"];
- }
- }
- //将IsEx设置为true,标明该节点已经展开
- this.dataGridView1.Rows[e.RowIndex].Cells["IsEx"].Value = "true";
- this.dataGridView1.Rows[e.RowIndex].Cells["EX"].Value = "-";

删除子节点:

- if (this.dataGridView1.Columns[e.ColumnIndex].Name == "EX" && isEx == "true")
- {
- string id = this.dataGridView1.Rows[e.RowIndex].Cells["ID"].Value.ToString();
- DataTable table = GetDataTable("select * from Department where DparentId=" + id);
- if (table.Rows.Count > )
- {
- //利用Remove
- for (int i = ; i < table.Rows.Count; i++)
- {
- foreach (DataGridViewRow row in this.dataGridView1.Rows)
- {
- if (row.Cells["ID"].Value.Equals(table.Rows[i]["ID"]))
- {
- this.dataGridView1.Rows.Remove(row);
- }
- }
- }
- }
- ////将IsEx设置为false,标明该节点已经收缩
- this.dataGridView1.Rows[e.RowIndex].Cells["IsEx"].Value = "false";
- this.dataGridView1.Rows[e.RowIndex].Cells["EX"].Value = "+";
- }

这里面通过比较ID来唯一确定一行,循环比较多,因为子节点是紧接着父节点的,我们可以确定子节点所在的行数,所以用RemoveAt()方法更好。
- //利用RemoveAt
- for (int i = table.Rows.Count; i > ; i--)
- {
- //删除行
- this.dataGridView1.Rows.RemoveAt(i + e.RowIndex);
- }
上面的做法是通过不断的插入与删除来实现,但这样与数据库的交互变得很频繁。更好的做法应该是插入一次,然后通过隐藏或显示行来实现我们的效果。
为此,我们还要在grid中新增两个列:
IsInsert:用来判断该行是否已经有插入子节点数据
RowCount:用来保存该行下插入的子节点数量。
在方法DataGridBing中,绑定数据时,应该再加一列:
- //是否插入
- row.Cells["IsInsert"].Value = "false";
而在增加节点的时候,我们要多做一个判断,如果IsInsert为false就插入数据,如果为true就显示数据
- if (this.dataGridView1.Columns[e.ColumnIndex].Name == "EX" && isEx=="false")
- {
- if (this.dataGridView1.Rows[e.RowIndex].Cells["IsInsert"].Value.ToString() == "false")
- {
- string id = this.dataGridView1.Rows[e.RowIndex].Cells["ID"].Value.ToString();
- DataTable table = GetDataTable("select * from Department where DparentId=" + id);
- if (table.Rows.Count > )
- {
- //插入行
- this.dataGridView1.Rows.Insert(e.RowIndex + , table.Rows.Count);
- for (int i = ; i < table.Rows.Count; i++)
- {
- DataGridViewRow row = this.dataGridView1.Rows[e.RowIndex + i + ];
- row.DefaultCellStyle.BackColor = Color.CadetBlue;
- row.Cells["ID"].Value = table.Rows[i]["ID"];
- row.Cells["DName"].Value = table.Rows[i]["DName"];
- row.Cells["Daddress"].Value = table.Rows[i]["Daddress"];
- row.Cells["Dtelphone"].Value = table.Rows[i]["Dtelphone"];
- }
- this.dataGridView1.Rows[e.RowIndex].Cells["IsInsert"].Value = "true";
- this.dataGridView1.Rows[e.RowIndex].Cells["RowCount"].Value = table.Rows.Count;
- }
- }
- else
- {
- //显示数据
- int RowCount = Convert.ToInt32(this.dataGridView1.Rows[e.RowIndex].Cells["RowCount"].Value);
- for (int i = ; i <= RowCount; i++)
- {
- this.dataGridView1.Rows[e.RowIndex + i].Visible = true;
- }
- }
- //将IsEx设置为true,标明该节点已经展开
- this.dataGridView1.Rows[e.RowIndex].Cells["IsEx"].Value = "true";
- this.dataGridView1.Rows[e.RowIndex].Cells["EX"].Value = "-";
- }
收缩的时候,我们直接隐藏行就可以了.
- if (this.dataGridView1.Columns[e.ColumnIndex].Name == "EX" && isEx == "true")
- {
- int RowCount = Convert.ToInt32(this.dataGridView1.Rows[e.RowIndex].Cells["RowCount"].Value);
- for (int i = ; i <= RowCount; i++)
- {
- //隐藏行
- this.dataGridView1.Rows[e.RowIndex + i].Visible = false;
- }
- ////将IsEx设置为false,标明该节点已经收缩
- this.dataGridView1.Rows[e.RowIndex].Cells["IsEx"].Value = "false";
- this.dataGridView1.Rows[e.RowIndex].Cells["EX"].Value = "+";
- }
DataGridView之行的展开与收缩的更多相关文章
- ios知识点总结——UITableView的展开与收缩及横向Table
UITableVIew是iOS开发中使用最为广泛的一种控件,对于UITableView的基本用法本文不做探讨,本文主要是针对UITableView的展开与收缩进行阐述,在文章的后面也会探讨一下横向ta ...
- ios-tableViewcell展开与收缩动画处理
[前言] 在使用华尔街见闻 app 时,看到它的 tableVeiw 上的 cell 具有很好的展开与收缩功能.于是自己想了一下实现,感觉应该挺简单的,于是心痒痒写个 demo 实现一波.华尔街见闻 ...
- Ext.grid rowexpander的展开与收缩
这里写Ext.grid.Panel的展开与收缩. 1. 确保在grid存在rowexpander对象: plugins: [{ ptype: 'rowexpander', rowBodyTpl: [' ...
- C# DataGridView显示行号的三种方法
方法一: 网上最常见的做法是用DataGridView的RowPostPaint事件在RowHeaderCell中绘制行号: private void dgGrid_RowPostPaint( obj ...
- DataGridView显示行号的几种方法来自http://www.soaspx.com/dotnet/csharp/csharp_20100204_2740.html
方法一: 网上最常见的做法是用DataGridView的RowPostPaint事件在RowHeaderCell中绘制行号: private void dataGridView1_RowPostPai ...
- 【转】DataGridView显示行号
ref:http://blog.csdn.net/xieyufei/article/details/9769631 方法一: 网上最常见的做法是用DataGridView的RowPostPaint事件 ...
- dhtmlxtree 节点 展开收缩:新增了直接点 文本内容 也 实现了 展开收缩 功能(并记住了展开、收缩状态)
dhtmlxtree 节点 展开收缩通常情况我们按 +- 就实现了 展开收缩 功能,为了方便我们新增了直接点 文本内容 也 实现了 展开收缩 功能(并记住了展开.收缩状态) tree = new dh ...
- js 实现内容的展开和收缩
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Winform中的DatagridView显示行号
1.设置 RowPostPaint 为true 2.启用RowPostPaint事件 /// <summary> /// DataGridView显示行号 /// </summary ...
随机推荐
- 设置Linux时间 同步时间
date命令将日期设置为2014年6月18日 ---- date -s 06/18/14 将时间设置为14点20分50秒 ---- date -s 14:20:50 将时间设置为2014年6月 ...
- jquery.tmpl.min.js--前端实现模版--数据绑定--详解
动态请求数据来更新页面是现在非常常用的方法,比如博客评论的分页动态加载,微博的滚动加载和定时请求加载等. 这些情况下,动态请求返回的数据一般不是已拼好的 HTML 就是 JSON 或 XML,总之不在 ...
- git服务器简易搭建法
受尽svn各种折磨的小伙伴都听说过git. 但是网上一搜索, 本来打算跟svn一样. 下一个服务器, 装下就可以开始用了. 没想到啊, 没想到. 居然需要Linux天赋点… 好吧, 拜鸟哥门下把Lin ...
- Delphi XE5教程12:注释和编译器指示字
内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误!也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者可 ...
- How to change Form & Property & Report font for current User [AX2012]
对于我们开发人员来说,系统默认的字体,本人实在不喜欢,尤其是属性字体[太小,太细,根本看不清],每次做一个新项目[AX2012]第一件事就是更改字体. 由于AX2012没有像AX2009那样,可以工具 ...
- python autopy
今天学习了python autopy 主要包括alert,color,mouse,key,bitmap,screen等的操作 文档在http://www.autopy.org/documentatio ...
- JDBC 基本操作: CRUD
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可. Statement对象的executeUpdate方法,用于向 ...
- Java中main函数参数String args[] 和 String[] args 区别
其实没什么区别的:当初我也是这样的疑问,呵呵:非要说区别就看下面:执行效果上没有不同, 但在语法意义上略有不同. 比如, String与String[], 前者叫字符串类型而后者叫字符串数组类型. S ...
- javascript实现播放音乐
<script language="javascript"> var flag = 0; //控制变量放在函数内起不到作用.function openplay() { ...
- [转载+原创]Emgu CV on C# (六) —— Emgu CV on Canny边缘检测
Canny边缘检测也是一种边缘检测方法,本文介绍了Canny边缘检测的函数及其使用方法,并利用emgucv方法将轮廓检测解算的结果与原文进行比较. 图像的边缘检测的原理是检测出图像中所有灰度值变化较大 ...