【Winform-自定义控件】 DataGridView多维表头
[datagridview与treeview绑定]
treeview

代码:
DataTable dtable = new DataTable("Rock");
//添加8列
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
dtable.Columns.Add("", typeof(System.String));
//添加一行数据
DataRow drow = dtable.NewRow();
drow[""] = "";
drow[""] = "";
drow[""] = "";
drow[""] = "";
drow[""] = "";
drow[""] = "";
drow[""] = "";
drow[""] = "";
dtable.Rows.Add(drow);
//绑定数据
multiColHeaderDgv2.DataSource = dtable;
datagridview多维表头实现效果:

自定义控件全部代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel; namespace myMultiColHeaderDgv
{
public class MultiColHeaderDgv:DataGridView
{ #region 字段定義 /// <summary>多維列標題的樹結構
///
/// </summary>
private TreeView _ColHeaderTreeView; /// <summary>樹的最大層數
///
/// </summary>
private int iNodeLevels; /// <summary>一維列標題的高度
///
/// </summary>
private int iCellHeight; /// <summary>所有葉節點
///
/// </summary>
private IList<TreeNode> ColLists = new List<TreeNode>(); #endregion #region 屬性定義 /// <summary>多維列標題的樹結構
///
/// </summary>
[
Description("多維列標題的樹結構")
]
public TreeView myColHeaderTreeView
{
get { return _ColHeaderTreeView; }
set { _ColHeaderTreeView = value; }
} #endregion #region 方法函數 /// <summary>遞歸計算樹最大層數,並保存所有葉節點
///
/// </summary>
/// <param name="tnc"></param>
/// <returns></returns>
private int myGetNodeLevels(TreeNodeCollection tnc)
{
if (tnc == null) return ; foreach (TreeNode tn in tnc)
{
if ((tn.Level + ) > iNodeLevels)//tn.Level是從0開始的
{
iNodeLevels = tn.Level+;
} if (tn.Nodes.Count > )
{
myGetNodeLevels(tn.Nodes);
}
else
{
ColLists.Add(tn);//葉節點
}
} return iNodeLevels;
} /// <summary>調用遞歸求最大層數、列頭總高
///
/// </summary>
public void myNodeLevels()
{ iNodeLevels = ;//初始為1 ColLists.Clear(); int iNodeDeep = myGetNodeLevels(_ColHeaderTreeView.Nodes); iCellHeight = this.ColumnHeadersHeight; this.ColumnHeadersHeight = this.ColumnHeadersHeight * iNodeDeep;//列頭總高=一維列高*層數 } /// <summary>获得合并标题字段的宽度
///
/// </summary>
/// <param name="node">字段节点</param>
/// <returns>字段宽度</returns>
private int GetUnitHeaderWidth(TreeNode node)
{
int uhWidth = ;
//获得最底层字段的宽度
if (node.Nodes == null)
return this.Columns[GetColumnListNodeIndex(node)].Width; if (node.Nodes.Count == )
return this.Columns[GetColumnListNodeIndex(node)].Width; //获得非最底层字段的宽度
for (int i = ; i <= node.Nodes.Count - ; 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 = ; i <= ColLists.Count - ; i++)
{
if (ColLists[i].Equals(node))
return i;
}
return -;
} ///<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 == )
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 == )
{
uhRectangle = new Rectangle(e.CellBounds.Left,
e.CellBounds.Top + node.Level * iCellHeight,
uhWidth - ,
iCellHeight * (iNodeLevels - node.Level) - );
}
else
{
uhRectangle = new Rectangle(
e.CellBounds.Left,
e.CellBounds.Top + node.Level * iCellHeight,
uhWidth - ,
iCellHeight - );
} //画矩形
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.ColumnHeadersDefaultCellStyle.Font
, Brushes.Black
, uhRectangle.Left + uhRectangle.Width / -
e.Graphics.MeasureString(node.Text, this.ColumnHeadersDefaultCellStyle.Font).Width / -
, uhRectangle.Top +
uhRectangle.Height / - e.Graphics.MeasureString(node.Text, this.ColumnHeadersDefaultCellStyle.Font).Height / ); //递归调用()
if (node.PrevNode == null)
if (node.Parent != null)
PaintUnitHeader(node.Parent, e, level - );
} #endregion //重寫表頭
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
try
{
//行标题不重写
if (e.ColumnIndex < )
{
base.OnCellPainting(e);
return;
} if (iNodeLevels == )
{
base.OnCellPainting(e);
return;
} //绘制表头
if (e.RowIndex == -)
{
if (_ColHeaderTreeView != null)
{
if (iNodeLevels == )
{
myNodeLevels();
} PaintUnitHeader((TreeNode)this.ColLists[e.ColumnIndex], e, iNodeLevels); e.Handled = true;
}
else
{
base.OnCellPainting(e);
}
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
}
}
}
using System;using System.Collections.Generic;using System.Text;using System.Windows.Forms;using System.Drawing;using System.ComponentModel;
namespace myMultiColHeaderDgv{ public class MultiColHeaderDgv:DataGridView {
#region 字段定義
/// <summary>多維列標題的樹結構 /// /// </summary> private TreeView _ColHeaderTreeView; /// <summary>樹的最大層數 /// /// </summary> private int iNodeLevels;
/// <summary>一維列標題的高度 /// /// </summary> private int iCellHeight;
/// <summary>所有葉節點 /// /// </summary> private IList<TreeNode> ColLists = new List<TreeNode>();
#endregion
#region 屬性定義
/// <summary>多維列標題的樹結構 /// /// </summary> [ Description("多維列標題的樹結構") ] public TreeView myColHeaderTreeView { get { return _ColHeaderTreeView; } set { _ColHeaderTreeView = value; } }
#endregion
#region 方法函數
/// <summary>遞歸計算樹最大層數,並保存所有葉節點 /// /// </summary> /// <param name="tnc"></param> /// <returns></returns> private int myGetNodeLevels(TreeNodeCollection tnc) { if (tnc == null) return 0;
foreach (TreeNode tn in tnc) { if ((tn.Level + 1) > iNodeLevels)//tn.Level是從0開始的 { iNodeLevels = tn.Level+1; }
if (tn.Nodes.Count > 0) { myGetNodeLevels(tn.Nodes); } else { ColLists.Add(tn);//葉節點 } }
return iNodeLevels; }
/// <summary>調用遞歸求最大層數、列頭總高 /// /// </summary> public void myNodeLevels() {
iNodeLevels = 1;//初始為1
ColLists.Clear();
int iNodeDeep = myGetNodeLevels(_ColHeaderTreeView.Nodes);
iCellHeight = this.ColumnHeadersHeight;
this.ColumnHeadersHeight = this.ColumnHeadersHeight * iNodeDeep;//列頭總高=一維列高*層數
}
/// <summary>获得合并标题字段的宽度 /// /// </summary> /// <param name="node">字段节点</param> /// <returns>字段宽度</returns> 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 <= ColLists.Count - 1; i++) { if (ColLists[i].Equals(node)) return i; } return -1; }
///<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 * iCellHeight, uhWidth - 1, iCellHeight * (iNodeLevels - node.Level) - 1); } else { uhRectangle = new Rectangle( e.CellBounds.Left, e.CellBounds.Top + node.Level * iCellHeight, uhWidth - 1, iCellHeight - 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.ColumnHeadersDefaultCellStyle.Font , Brushes.Black , uhRectangle.Left + uhRectangle.Width / 2 - e.Graphics.MeasureString(node.Text, this.ColumnHeadersDefaultCellStyle.Font).Width / 2 - 1 , uhRectangle.Top + uhRectangle.Height / 2 - e.Graphics.MeasureString(node.Text, this.ColumnHeadersDefaultCellStyle.Font).Height / 2);
//递归调用() if (node.PrevNode == null) if (node.Parent != null) PaintUnitHeader(node.Parent, e, level - 1); }
#endregion
//重寫表頭 protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e) { try { //行标题不重写 if (e.ColumnIndex < 0) { base.OnCellPainting(e); return; }
if (iNodeLevels == 1) { base.OnCellPainting(e); return; }
//绘制表头 if (e.RowIndex == -1) { if (_ColHeaderTreeView != null) { if (iNodeLevels == 0) { myNodeLevels(); }
PaintUnitHeader((TreeNode)this.ColLists[e.ColumnIndex], e, iNodeLevels);
e.Handled = true; } else { base.OnCellPainting(e); } } } catch (Exception ex) { MessageBox.Show(this, ex.Message, "Error"); } } }}
【Winform-自定义控件】 DataGridView多维表头的更多相关文章
- (转)DataGridView多维表头及其扩展功能
dataGridView1.RowHeadersVisible = false;把整行选中那一列去掉.如果需要整行选中,新增一按钮列模拟实现.上源码:多维DataGridView 有个简易的方法: 1 ...
- C#中Winform程序中如何实现多维表头【不通过第三方报表程序】
问题:C#中Winform程序中如何实现多维表头. 在网上搜了很多方法,大多数方法对于我这种新手,看的都不是很懂.最后在新浪博客看到了一篇比较易懂的文章:[DataGridView二维表头与合并单元格 ...
- 【Winform-自定义控件】DataGridView 单元格合并和二维表头
DataGridView单元格合并和二维表头应用: //DataGridView绑定数据 DataTable dt = new DataTable(); dt.Columns.Add("); ...
- Datagridview 实现二维表头和行合并【转载】
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; u ...
- 如何通过DataGridView 实现单元格合并和二维表头
先看下实现出来的效果(这里随便写了几组数据,用来测试) 先初始一个DataGridView 设置哪几列 DataGridView 里男女这两列的 AutoSizeMode 可以设置Fill. publ ...
- (八十九)c#Winform自定义控件-自定义滚动条(treeview、panel、datagridview、listbox、listview、textbox)
官网 http://www.hzhcontrols.com/ 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kw ...
- C#winform自定义控件大全
对C# WinForm开发系列收集的控件使用方面进行整理, 加入了一些文章, 不断补充充实, 完善这方面. 基础 - 常用控件 C# WinForm开发系列 - CheckBox/Button/Lab ...
- 关于Winform下DataGridView中实现checkbox全选反选、同步列表项的处理
近期接手一个winform 项目,虽然之前有.net 的经验,但是对一些控件的用法还不是很熟悉. 这段时间将会记录一些在工作中遇到的坎坷以及对应的解决办法,写出来与大家分享并希望大神提出更好解决方法来 ...
- (三十二)c#Winform自定义控件-表格
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
随机推荐
- 记日杂-log4net组件使用
下面我给大家介绍一下记日杂-log4net组件使用,当程序发布有服务器上,有时出现了错误, 都不知道出现在那,所以log4net组件很好解决这个问题. 1.添加开发包,并对log4net.dll的引用 ...
- Oracle的查询-单行查询
单行函数:作用于一行,返回一个值 多行函数:作用于多行,返回一个值 字符函数 --小写变大写 select upper('yes') from dual; --YES --大写变小写 select u ...
- redis 持久化之 RDB & AOF
Redis 持久化实现方式 快照对数据某一时间点的完整备份.例如Linux 快照备份.Redis RDB.MySQL Dump. 日志将数据的所有操作都记录到日志中,需要恢复时,将日志重新执行一次.M ...
- C++str.Format
C++应该没有这个函数,说的是Format是在MFC程序里看见的 Format是CString字符串类的成员函数CString::Format( LPCTSTR lpszFormat, ... ); ...
- 基于Springboot后台,前台 vue.js 跨域 Activiti6 工作流(用到websocket技术) 的项目
工作流模块----------------------------------------------------------------------------------------------- ...
- vue 动态添加对象属性
昨天使用vue发现直接给对象添加属性,并不能触发响应更新,后来看文档发现要通过this.$set 函数动态添加才可用,eg: this.$set( obj, key, data)
- centos7 源码安装 MongoDb
1.下载源码包 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.12.tgz 2.解压 放到 /usr/local/ ...
- python获取文件及文件夹大小
Python3.3下测试通过 获取文件大小 使用os.path.getsize函数,参数是文件的路径 获取文件夹大小 import os from os.path import join, getsi ...
- centos安装配置mariadb
CentOS7下使用yum安装MariaDB CentOS 6 或早期的版本中提供的是 MySQL 的服务器/客户端安装包,但 CentOS 7 已使用了 MariaDB 替代了默认的 MySQL.M ...
- 使用PyQt5自制文件查找工具,并生成EXE文件
一.工作中,有一个关键词查找工作,查找开发版本中使用的文本,有哪些词语是非法的,一个一个去查太累了,所以想到了用代码来实现.可后来想想,能否做成简单的小工具,大家都可以使用. 于是就着手编写工具.原来 ...