前几天Jo Muncher's Blog上看到《VS2005的DataGridView 多维合并标题 功能拓展》的文章,对我制作DataGridView多表头大有帮助,并把代码进行了调试,发现还有问题。近日把VB代码修改成C#代码,并对部分BUG进行修改,最终还是把问题攻克了,效果比较理想。见下图
源代码如下:
HeaderUnitView.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Sql;
using System.Text;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DataGridViewSampCs
...{
public partial class HeaderUnitView : DataGridView
...{
private TreeView[] _columnTreeView;
private ArrayList _columnList = new ArrayList();
private int _cellHeight = 17;
private int _columnDeep = 1;
/**//// <summary>
/// 构造函数
/// </summary>
public HeaderUnitView()
...{
InitializeComponent();
}
[Description("设置或获得合并表头树的深度")]
public int ColumnDeep
...{
get
...{
if (this.Columns.Count == 0)
_columnDeep = 1;
this.ColumnHeadersHeight = _cellHeight * _columnDeep;
return _columnDeep;
}
set
...{
if (value < 1)
_columnDeep = 1;
else
_columnDeep = value;
this.ColumnHeadersHeight = _cellHeight * _columnDeep;
}
}
[Description("添加合并式单元格绘制的所需要的节点对象")]
public TreeView[] ColumnTreeView
...{
get ...{ return _columnTreeView; }
set
...{
if (_columnTreeView != null)
...{
for (int i = 0; i <= _columnTreeView.Length - 1; i++)
_columnTreeView[i].Dispose();
}
_columnTreeView = value;
}
}
[Description("设置添加的字段树的相关属性")]
public TreeView ColumnTreeViewNode
...{
get ...{ return _columnTreeView[0]; }
}
public ArrayList NadirColumnList
...{
get
...{
if (_columnTreeView == null)
return null;
if (_columnTreeView[0] == null)
return null;
if (_columnTreeView[0].Nodes == null)
return null;
if (_columnTreeView[0].Nodes.Count == 0)
return null;
_columnList.Clear();
GetNadirColumnNodes(_columnList, _columnTreeView[0].Nodes[0], false);
return _columnList;
}
}
/**////<summary>
///绘制合并表头
///</summary>
///<param name="node">合并表头节点</param>
///<param name="e">绘图参数集</param>
///<param name="level">结点深度</param>
///<remarks></remarks>
public void PaintUnitHeader(
TreeNode node,
System.Windows.Forms.DataGridViewCellPaintingEventArgs e,
int level)
...{
//根节点时退出递归调用
if (level == 0)
return;
RectangleF uhRectangle;
int uhWidth;
SolidBrush gridBrush = new SolidBrush(this.GridColor);
SolidBrush backColorBrush = new SolidBrush(e.CellStyle.BackColor);
Pen gridLinePen = new Pen(gridBrush);
StringFormat textFormat = new StringFormat();
textFormat.Alignment = StringAlignment.Center;
uhWidth = GetUnitHeaderWidth(node);
//与原贴算法有所区别在这。
if( node.Nodes.Count == 0)
...{
uhRectangle = new Rectangle(e.CellBounds.Left,
e.CellBounds.Top + node.Level * _cellHeight,
uhWidth - 1,
_cellHeight * (_columnDeep - node.Level) - 1);
}
else
...{
uhRectangle = new Rectangle(
e.CellBounds.Left,
e.CellBounds.Top + node.Level * _cellHeight,
uhWidth - 1,
_cellHeight - 1);
}
//画矩形
e.Graphics.FillRectangle(backColorBrush, uhRectangle);
//划底线
e.Graphics.DrawLine(gridLinePen
, uhRectangle.Left
, uhRectangle.Bottom
, uhRectangle.Right
, uhRectangle.Bottom);
//划右端线
e.Graphics.DrawLine(gridLinePen
, uhRectangle.Right
, uhRectangle.Top
, uhRectangle.Right
, uhRectangle.Bottom);
/**/////写字段文本
//e.Graphics.DrawString(node.Text
// , this.Font
// , Brushes.Black
// , uhRectangle
// , textFormat);
e.Graphics.DrawString(node.Text, this.Font
, Brushes.Black
, uhRectangle.Left +uhRectangle.Width / 2-
e.Graphics.MeasureString(node.Text, this.Font).Width / 2 - 1
, uhRectangle.Top +
uhRectangle.Height / 2 -e.Graphics.MeasureString(node.Text, this.Font).Height / 2);
/**/////递归调用()
if (node.PrevNode == null)
if (node.Parent != null)
PaintUnitHeader(node.Parent, e, level - 1);
}
/**////判断节点是否为单一的
//private Boolean IsSingleChildNode(TreeNode node)
//{
// if (node.Nodes == null)
// return false;
// if (node.Nodes.Count == 0)
// return false;
// if (node.Nodes.Count == 1)
// return true;
// return false;
//}
/**//// <summary>
/// 获得合并标题字段的宽度
/// </summary>
/// <param name="node">字段节点</param>
/// <returns>字段宽度</returns>
/// <remarks></remarks>
private int GetUnitHeaderWidth(TreeNode node)
...{
//获得非最底层字段的宽度
int uhWidth = 0;
//获得最底层字段的宽度
if (node.Nodes == null)
return this.Columns[GetColumnListNodeIndex(node)].Width;
if (node.Nodes.Count == 0)
return this.Columns[GetColumnListNodeIndex(node)].Width;
for (int i = 0; i <= node.Nodes.Count - 1; i++)
...{
uhWidth = uhWidth + GetUnitHeaderWidth(node.Nodes[i]);
}
return uhWidth;
}
/**//// <summary>
/// 获得底层字段索引
/// </summary>
///' <param name="node">底层字段节点</param>
/// <returns>索引</returns>
/// <remarks></remarks>
private int GetColumnListNodeIndex(TreeNode node)
...{
for (int i = 0; i <= _columnList.Count - 1; i++)
...{
if (((TreeNode)_columnList[i]).Equals(node))
return i;
}
return -1;
}
/**//// <summary>
/// 获得底层字段集合
/// </summary>
/// <param name="alList">底层字段集合</param>
/// <param name="node">字段节点</param>
/// <param name="checked">向上搜索与否</param>
/// <remarks></remarks>
private void GetNadirColumnNodes(
ArrayList alList,
TreeNode node,
Boolean isChecked)
...{
if (isChecked == false)
...{
if (node.FirstNode == null)
...{
alList.Add(node);
if (node.NextNode != null)
...{
GetNadirColumnNodes(alList, node.NextNode, false);
return;
}
if (node.Parent != null)
...{
GetNadirColumnNodes(alList, node.Parent, true);
return;
}
}
else
...{
if (node.FirstNode != null)
...{
GetNadirColumnNodes(alList, node.FirstNode, false);
return;
}
}
}
else
...{
if (node.FirstNode == null)
...{
return;
}
else
...{
if (node.NextNode != null)
...{
GetNadirColumnNodes(alList, node.NextNode, false);
return;
}
if (node.Parent != null)
...{
GetNadirColumnNodes(alList, node.Parent, true);
return;
}
}
}
}
/**//// <summary>
/// 单元格绘制(重写)
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnCellPainting(System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
...{
//行标题不重写
if (e.ColumnIndex < 0)
...{
base.OnCellPainting(e);
return;
}
if (_columnDeep == 1)
...{
base.OnCellPainting(e);
return;
}
//绘制表头
if (e.RowIndex == -1)
...{
PaintUnitHeader((TreeNode)NadirColumnList[e.ColumnIndex]
,e
, _columnDeep);
e.Handled = true;
}
}
}
}
HeaderUnitView.Designer.cs(修改Dispose事件中的代码,其它的不用修改)
/**//// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
...{
if (_columnTreeView != null)
...{
for (int i = 0; i <= _columnTreeView.Length - 1; i++)
...{
_columnTreeView[i].Dispose();
}
}
if (disposing && (components != null))
...{
components.Dispose();
}
base.Dispose(disposing);
}
由于是Jo Muncher's 文章,这里不再多说了,如想知道更多,请点击下面连接。
http://blog.csdn.net/JoMuncher/archive/2007/11/02/1862977.aspx