一 重写表格
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DataGrideViewControl
{
public class DataGridViewGroupCell : DataGridViewTextBoxCell
{
#region Variant
/// <summary>
/// 标示的宽度
/// </summary>
const int PLUS_WIDTH = 24;
/// <summary>
/// 标示的区域
/// </summary>
Rectangle groupPlusRect;
#endregion
#region Init
public DataGridViewGroupCell()
{
groupLevel = 1;
}
#endregion
#region Property
int groupLevel;
/// <summary>
/// 组级别(以1开始)
/// </summary>
public int GroupLevel
{
get { return groupLevel; }
set { groupLevel = value; }
}
DataGridViewGroupCell parentCell;
/// <summary>
/// 父节点
/// </summary>
public DataGridViewGroupCell ParentCell
{
get
{
return parentCell;
}
set
{
if (value == null)
throw new NullReferenceException("父节点不可为空");
if (!(value is DataGridViewGroupCell))
throw new ArgumentException("父节点必须为 DataGridViewGroupCell 类型");
parentCell = value;
parentCell.AddChildCell(this);
}
}
private bool collapsed;
/// <summary>
/// 是否收起
/// </summary>
public bool Collapsed
{
get { return collapsed; }
}
private List<DataGridViewGroupCell> childCells = null;
/// <summary>
/// 所有的子结点
/// </summary>
public DataGridViewGroupCell[] ChildCells
{
get
{
if (childCells == null)
return null;
return childCells.ToArray();
}
}
/// <summary>
/// 取得组标示(有+或-号的框)的区域
/// </summary>
public Rectangle GroupPlusRect
{
get
{
return groupPlusRect;
}
}
bool bPaint = true;
/// <summary>
/// 是否重绘
/// </summary>
public bool BPaint
{
get { return bPaint; }
set { bPaint = value; }
}
#endregion
#region 添加子节点
/// <summary>
/// 添加子结点
/// </summary>
/// <param name="cell"></param>
/// <returns></returns>
public int AddChildCell(DataGridViewGroupCell cell)
{
return AddChildCellRange(new DataGridViewGroupCell[] { cell });
}
public int AddChildCellRange(DataGridViewGroupCell[] cells)
{
bool needRedraw = false;
if (childCells == null)
{
//需要画一个加号
childCells = new List<DataGridViewGroupCell>();
needRedraw = true;
}
foreach (DataGridViewGroupCell cell in cells)
{
childCells.Add(cell);
cell.groupLevel = groupLevel + 1;
cell.parentCell = this;
}
if (needRedraw)
{
DataGridView.InvalidateCell(this);
}
return childCells.Count;
}
#endregion
#region 绘制节点
protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (!bPaint)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
return;
}
Pen gridPen = new Pen(DataGridView.GridColor);
Brush bruBK = new SolidBrush(cellStyle.BackColor);
int width = groupLevel * PLUS_WIDTH;
Rectangle rectLeft = new Rectangle(cellBounds.Left, cellBounds.Top - 1, width, cellBounds.Height);
cellBounds.X += width;
cellBounds.Width -= width;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
PaintGroupPlus(graphics, gridPen, bruBK, cellStyle, rectLeft, collapsed);
gridPen.Dispose();
gridPen = null;
bruBK.Dispose();
bruBK = null;
}
private void PaintGroupPlus(Graphics graphics, Pen gridPen, Brush bruBK, DataGridViewCellStyle cellStyle, Rectangle rectLeft, bool collapsed)
{
Pen pen = new Pen(DataGridView.GridColor, 1);
pen.DashStyle = DashStyle.Dot;
graphics.FillRectangle(bruBK, rectLeft);
int left = rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH;
//画 Left, Top, Right 三根线
graphics.DrawLine(gridPen, left, rectLeft.Top, rectLeft.Right, rectLeft.Top);//上
graphics.DrawLine(gridPen, rectLeft.Right, rectLeft.Bottom, rectLeft.Left, rectLeft.Bottom);
//最左边的一条线
graphics.DrawLine(gridPen, rectLeft.Left, rectLeft.Top, rectLeft.Right, rectLeft.Top);
//如果是该级别的最后一个节点,则需要画一个底线,以便将整个组封闭起来
bool drawBottomLine = false;
for (int i = 1; i < groupLevel; i++)
{
if (!ParentCell.IsLastCell(ParentCell.groupLevel))//上层不是最后一个节点
{
graphics.DrawLine(pen, rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top
, rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Bottom);
}
}
//如果有子结点, 则需要画一个方框, 里面有+号或-号
if (childCells != null && childCells.Count > 0)
{
groupPlusRect = new Rectangle((groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 12) / 2
, rectLeft.Top + (rectLeft.Height - 12) / 2, 12, 12);
graphics.DrawRectangle(gridPen, groupPlusRect);
graphics.DrawLine(Pens.Black, groupPlusRect.Left + 3, groupPlusRect.Top + groupPlusRect.Height / 2
, groupPlusRect.Right - 3, groupPlusRect.Top + groupPlusRect.Height / 2);
if (collapsed)
{
graphics.DrawLine(Pens.Black, groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Top + 3
, groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Bottom - 3);
}
}
else
{
//横
graphics.DrawLine(pen, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top + rectLeft.Height / 2
, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH, rectLeft.Top + rectLeft.Height / 2);
//竖
if (!IsLastCell((groupLevel - 1)))
{
graphics.DrawLine(pen, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top
, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Bottom);
}
else
graphics.DrawLine(pen, (groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 8) / 2 + 4, rectLeft.Top + (rectLeft.Height - 8) / 2 - 6,
(groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 8) / 2 + 4, rectLeft.Top + (rectLeft.Height - 8) / 2 + 4);
}
pen.Dispose();
pen = null;
}
#endregion
#region 判断
/// <summary>
/// 该节点是否为某一级节点的最后一个子结点
/// </summary>
/// <param name="level">节点层级</param>
/// <returns></returns>
private bool IsLastCell(int level)
{
int row = DataGridView.Rows.GetNextRow(RowIndex, DataGridViewElementStates.None);
if (row == -1)
return true;
DataGridViewGroupCell cel = DataGridView.Rows[row].Cells[0] as DataGridViewGroupCell;
return (cel.GroupLevel == level);
}
#endregion
#region 点击 Cell
protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
{
Rectangle rect = DataGridView.GetCellDisplayRectangle(ColumnIndex, RowIndex, false);
Point pt = new Point(rect.Left + e.Location.X, rect.Top + e.Location.Y);
if (groupPlusRect.Contains(pt))
{
if (collapsed)
{
Expand();
}
else
{
Collapse();
}
}
base.OnMouseDown(e);
}
#endregion
#region 展开/收起节点
/// <summary>
/// 展开节点
/// </summary>
public void Expand()
{
if (parentCell != null)
{
parentCell.CollapseAll();
}
collapsed = false;
ShowChild(true);
base.DataGridView.InvalidateCell(this);
}
private void ShowChild(bool show)
{
if (childCells == null)
return;
foreach (DataGridViewGroupCell cel in childCells)
{
if (cel.RowIndex == -1)
{
continue;
}
DataGridView.Rows[cel.RowIndex].Visible = show;
if (!cel.collapsed)
cel.ShowChild(show);
}
}
/// <summary>
/// 收起节点
/// </summary>
public void Collapse()
{
collapsed = true;
ShowChild(false);
base.DataGridView.InvalidateCell(this);
}
/// <summary>
/// 展开节点及子结点
/// </summary>
public void ExpandAll()
{
if (childCells == null)
return;
foreach (DataGridViewGroupCell cel in childCells)
{
cel.ExpandAll();
}
}
public void CollapseAll()
{
if (childCells == null)
return;
foreach (DataGridViewGroupCell cel in childCells)
{
cel.CollapseAll();
}
}
#endregion
}
public class DataGridViewGroupColumn : DataGridViewTextBoxColumn
{
public DataGridViewGroupColumn()
{
CellTemplate = new DataGridViewGroupCell();
ReadOnly = true;
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if ((value != null) && !(value is DataGridViewGroupCell))
{
throw new InvalidCastException("Need System.Windows.Forms.DataGridViewGroupCell");
}
base.CellTemplate = value;
}
}
}
public class DefineDataGridView : DataGridView
{
bool showRowHeaderNumbers;
///
/// 是否显示行号
///
/// [Description(“是否显示行号”), DefaultValue(true)]
public bool ShowRowHeaderNumbers
{
get { return showRowHeaderNumbers; }
set
{
if (showRowHeaderNumbers != value)
Invalidate();
showRowHeaderNumbers = value;
}
}
public DefineDataGridView()
{
showRowHeaderNumbers = true;
this.RowHeadersWidth = 30;
this.AllowUserToAddRows = false;
}
}
}
二 应用举例
新建窗体程序
在form中添加datagridviw控件
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DataGrideViewControl
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//添加重新绘制后可以折叠的列表
dataGridView1.Columns.Insert(0, new DataGridViewGroupColumn());
//添加正常的列表
dataGridView1.Columns.Insert(1, new DataGridViewTextBoxColumn());
dataGridView1.Columns.Insert(2, new DataGridViewTextBoxColumn());
DataGridViewGroupCell MainCell = new DataGridViewGroupCell();
MainCell.Value = "主目录";
DataGridViewGroupCell ChildCell1 = new DataGridViewGroupCell();
ChildCell1.Value = "子目录1";
DataGridViewGroupCell ChildCell2 = new DataGridViewGroupCell();
ChildCell2.Value = "子目录2";
Addcolumn(ChildCell2);
Addcolumn(ChildCell1);
Addcolumn(MainCell);
MainCell.AddChildCell(ChildCell1);
MainCell.AddChildCell(ChildCell2);
}
private void Addcolumn(DataGridViewCell Mcell)
{
//补充绘制目标单元格
DataGridViewRow row = new DataGridViewRow();
row.Cells.Add(Mcell);
//补充正常单元格作对比
DataGridViewCell EmptyCell = new DataGridViewTextBoxCell();
DataGridViewCell EmptyCell2 = new DataGridViewTextBoxCell();
row.Cells.Add(EmptyCell);
row.Cells.Add(EmptyCell2);
dataGridView1.Rows.Insert(0, row);
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
}
}
结果