基于原生DataGridView实现折叠/展开
最近实现一个需求,需要利用Winform原生DataGridView实现折叠/展开的效果,我这里对实现过程进行总结一下。
首先需要设计数据类结构:
public class DataItem { public bool? Expanded { get; set; } //是否展开 null-代表子项,不可折叠/展开 true-展开 false-折叠(用于显示不同的图标) public bool Checked { get; set; } //是否勾选 public long Id { get; set; } public string Name { get; set; } public string Description { get; set; } public bool Visible { get; set; } = true; }
UI设计:
第一列类型为DataGridViewImageColumn
第二列类型为DataGridViewCheckBoxColumn
加载测试数据:
private void Form1_Load(object sender, EventArgs e) { List<DataItem> dataItems = new List<DataItem>() { new DataItem(){Expanded=true,Id=100,Name="门诊部"}, new DataItem(){Id=101,Name="儿科门诊",Description="专为儿童服务,限制年龄"}, new DataItem(){Id=102,Name="妇科门诊",Description="转为女性服务,限制性别"}, new DataItem(){Id=103,Name="内科门诊",Description="内科"}, new DataItem(){Expanded=true,Id=200,Name="住院部"}, new DataItem(){Id=201,Name="泌尿科",Description="泌尿专科"}, new DataItem(){Id=202,Name="骨伤科",Description="骨科专科"}, new DataItem(){Id=203,Name="妇产科",Description="妇科+产科"}, new DataItem(){Id=204,Name="消化科",Description="消化科"}, }; dataItemDataGridView.Rows.Clear(); foreach (DataItem dataItem in dataItems) { int count = dataItemDataGridView.Rows.Count; dataItemDataGridView.Rows.Insert(dataItemDataGridView.Rows.Count, new object[] { !dataItem.Expanded.HasValue ? _blankImage : dataItem.Expanded.Value ? _minusImage : _plusImage, dataItem.Checked, dataItem.Name, dataItem.Description, dataItem.Id }); dataItemDataGridView.Rows[count].Tag = dataItem; dataItemDataGridView.Rows[count].Visible = dataItem.Visible; } }
实现折叠/展开,选择父节点是全选/取消全选
private void dataItemDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { DataGridViewRowCollection rows = dataItemDataGridView.Rows; if (e.ColumnIndex == 0) { Image image = rows[e.RowIndex].Cells[_imageColumnName].Value as Image; bool isChecked = (bool)rows[e.RowIndex].Cells[_checkedColumnName].Value; string name = rows[e.RowIndex].Cells[_nameColumnName].Value as string; if (image == _plusImage) { dataItemDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = _minusImage; int index = e.RowIndex + 1; while (index < rows.Count && rows[index].Cells[_imageColumnName].Value != _plusImage && rows[index].Cells[_imageColumnName].Value != _minusImage) { dataItemDataGridView.Rows[index].Visible = true; index++; } } else if (image == _minusImage) { dataItemDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = _plusImage; int index = e.RowIndex + 1; while (index < rows.Count && rows[index].Cells[_imageColumnName].Value != _plusImage && rows[index].Cells[_imageColumnName].Value != _minusImage) { dataItemDataGridView.Rows[index].Visible = false; index++; } } } else if (e.ColumnIndex == 1) { bool isChecked = !(bool)rows[e.RowIndex].Cells[_checkedColumnName].Value; dataItemDataGridView.Rows[e.RowIndex].Cells[_checkedColumnName].Value = isChecked; DataItem dataItem = dataItemDataGridView.Rows[e.RowIndex].Tag as DataItem; dataItem.Checked = isChecked; Image image = rows[e.RowIndex].Cells[_imageColumnName].Value as Image; if (image == _plusImage || image == _minusImage) { int index = e.RowIndex + 1; while (index < rows.Count && rows[index].Cells[_imageColumnName].Value != _plusImage && rows[index].Cells[_imageColumnName].Value != _minusImage) { dataItemDataGridView.Rows[index].Cells[_checkedColumnName].Value = isChecked; dataItem = dataItemDataGridView.Rows[index].Tag as DataItem; dataItem.Checked = isChecked; index++; } } else { bool isGroupAllChecked = true; int index = e.RowIndex; while (index < rows.Count && rows[index].Cells[_imageColumnName].Value != _plusImage && rows[index].Cells[_imageColumnName].Value != _minusImage) { if (!(bool)rows[index].Cells[_checkedColumnName].Value) isGroupAllChecked = false; index++; } index = e.RowIndex - 1; while (index >= 0 && rows[index].Cells[_imageColumnName].Value != _plusImage && rows[index].Cells[_imageColumnName].Value != _minusImage) { if (!(bool)rows[index].Cells[_checkedColumnName].Value) isGroupAllChecked = false; index--; } if (index >= 0 && (bool)rows[index].Cells[_checkedColumnName].Value != isGroupAllChecked) dataItemDataGridView.Rows[index].Cells[_checkedColumnName].Value = isGroupAllChecked; } } } } private void dataItemDataGridView_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) { if (e.RowIndex >= 0) { DataGridViewRowCollection rows = dataItemDataGridView.Rows; if (rows[e.RowIndex].Cells[_imageColumnName].Value == _plusImage || rows[e.RowIndex].Cells[_imageColumnName].Value == _minusImage) { using (Brush backColorBrush = new SolidBrush(SystemColors.Control), fontBrush = new SolidBrush(SystemColors.ControlDark)) { e.Graphics.FillRectangle(backColorBrush, e.RowBounds.X + 46, e.RowBounds.Y, dataItemDataGridView.Width, e.RowBounds.Height - 1); using (Font font = new Font(Font.FontFamily.Name, Font.Size, FontStyle.Bold)) { e.Graphics.DrawString(rows[e.RowIndex].Cells[_nameColumnName].Value as string, font, fontBrush, e.RowBounds.X + 48, e.RowBounds.Y + 2); } } } } } private readonly Image _plusImage = Resource.Plus; private readonly Image _minusImage = Resource.Minus; private readonly Image _blankImage = Resource.Blank; private readonly string _imageColumnName = "imageColumn"; private readonly string _checkedColumnName = "checkedColumn"; private readonly string _nameColumnName = "deptNameColumn";
其中 Resource.Plus、Resource.Minus、Resource.Blank为图标资源文件
效果图:
没法插入本地视频,没法演示效果。需要源代码自取:https://github.com/Freelooppowter/HierarchyForm.git
本文来自博客园,作者:业荒于嬉,转载请注明原文链接:https://www.cnblogs.com/FreeLoopPowter/p/17109746.html
如内容对您有所帮助,还请不吝推荐一下!