问题:C#中Winform程序中如何实现多维表头。

在网上搜了很多方法,大多数方法对于我这种新手,看的都不是很懂。最后在新浪博客看到了一篇比较易懂的文章:【DataGridView二维表头与合并单元格】

大体的思路如下:

1.新建一个项目:

2.右键项目名称添加一个组件名为:HeaderUnitView.cs

3.点击【单击此处切换到代码视图】代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.Diagnostics;namespace WindowsFormsApplication1
{public partial class HeaderUnitView : DataGridView{private TreeView[] _columnTreeView;private ArrayList _columnList = new ArrayList();private int _cellHeight = 17;public int CellHeight{get { return _cellHeight; }set { _cellHeight = value; }}private int _columnDeep = 1;private bool HscrollRefresh = false;/// <summary>  /// 水平滚动时是否刷新表头,数据较多时可能会闪烁,不刷新时可能显示错误  /// </summary>  [Description("水平滚动时是否刷新表头,数据较多时可能会闪烁,不刷新时可能显示错误")]public bool RefreshAtHscroll{get { return HscrollRefresh; }set { HscrollRefresh = value; }}/// <summary>/// 构造函数/// </summary>public HeaderUnitView(){InitializeComponent();this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;//设置列高度显示模式              }public HeaderUnitView(IContainer container){container.Add(this);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]; }}/// <summary>/// 设置或获取合并列的集合/// </summary>[MergableProperty(false)][Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))][DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Visible)][Localizable(true)][Description("设置或获取合并列的集合"), Browsable(true), Category("单元格合并")]public List<string> MergeColumnNames{get{return _mergecolumnname;}set{_mergecolumnname = value;}}private List<string> _mergecolumnname = new List<string>();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, new SolidBrush(e.CellStyle.ForeColor), 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);}/// <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>  protected override void OnScroll(ScrollEventArgs e){bool scrollDirection = (e.ScrollOrientation == ScrollOrientation.HorizontalScroll);base.OnScroll(e);if (RefreshAtHscroll && scrollDirection)this.Refresh();}/// <summary>  /// 列宽度改变的重写  /// </summary>  /// <param name="e"></param>  protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e){Graphics g = Graphics.FromHwnd(this.Handle);float uwh = g.MeasureString(e.Column.HeaderText, this.Font).Width;if (uwh >= e.Column.Width) { e.Column.Width = Convert.ToInt16(uwh); }base.OnColumnWidthChanged(e);}/// <summary>  /// 单元格绘制(重写)  /// </summary>  /// <param name="e"></param>  /// <remarks></remarks>  protected override void OnCellPainting(System.Windows.Forms.DataGridViewCellPaintingEventArgs e){try{if (e.RowIndex > -1 && e.ColumnIndex > -1){DrawCell(e);}else{//行标题不重写  if (e.ColumnIndex < 0){base.OnCellPainting(e);return;}if (_columnDeep == 1){base.OnCellPainting(e);return;}//绘制表头  if (e.RowIndex == -1){if (e.ColumnIndex >= NadirColumnList.Count) { e.Handled = true; return; }PaintUnitHeader((TreeNode)NadirColumnList[e.ColumnIndex], e, _columnDeep);e.Handled = true;}}}catch{ }}#region 合并单元格/// <summary>/// 画单元格/// </summary>/// <param name="e"></param>private void DrawCell(DataGridViewCellPaintingEventArgs e){if (e.CellStyle.Alignment == DataGridViewContentAlignment.NotSet){e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;}Brush gridBrush = new SolidBrush(this.GridColor);SolidBrush backBrush = new SolidBrush(e.CellStyle.BackColor);SolidBrush fontBrush = new SolidBrush(e.CellStyle.ForeColor);int cellwidth;//上面相同的行数int UpRows = 0;//下面相同的行数int DownRows = 0;//总行数int count = 0;if (this.MergeColumnNames.Contains(this.Columns[e.ColumnIndex].Name) && e.RowIndex != -1){cellwidth = e.CellBounds.Width;Pen gridLinePen = new Pen(gridBrush);string curValue = e.Value == null ? "" : e.Value.ToString().Trim();string curSelected = this.CurrentRow.Cells[e.ColumnIndex].Value == null ? "" : this.CurrentRow.Cells[e.ColumnIndex].Value.ToString().Trim();if (!string.IsNullOrEmpty(curValue)){#region 获取下面的行数for (int i = e.RowIndex; i < this.Rows.Count; i++){if (this.Rows[i].Cells[e.ColumnIndex].Value.ToString().Equals(curValue)){//this.Rows[i].Cells[e.ColumnIndex].Selected = this.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;DownRows++;if (e.RowIndex != i){cellwidth = cellwidth < this.Rows[i].Cells[e.ColumnIndex].Size.Width ? cellwidth : this.Rows[i].Cells[e.ColumnIndex].Size.Width;}}else{break;}}#endregion#region 获取上面的行数for (int i = e.RowIndex; i >= 0; i--){if (this.Rows[i].Cells[e.ColumnIndex].Value.ToString().Equals(curValue)){//this.Rows[i].Cells[e.ColumnIndex].Selected = this.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;UpRows++;if (e.RowIndex != i){cellwidth = cellwidth < this.Rows[i].Cells[e.ColumnIndex].Size.Width ? cellwidth : this.Rows[i].Cells[e.ColumnIndex].Size.Width;}}else{break;}}#endregioncount = DownRows + UpRows - 1;if (count < 2){return;}}if (this.Rows[e.RowIndex].Selected){backBrush.Color = e.CellStyle.SelectionBackColor;fontBrush.Color = e.CellStyle.SelectionForeColor;}//以背景色填充e.Graphics.FillRectangle(backBrush, e.CellBounds);//画字符串PaintingFont(e, cellwidth, UpRows, DownRows, count);if (DownRows == 1){e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);count = 0;}// 画右边线e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1, e.CellBounds.Top, e.CellBounds.Right - 1, e.CellBounds.Bottom);e.Handled = true;}}/// <summary>/// 画字符串/// </summary>/// <param name="e"></param>/// <param name="cellwidth"></param>/// <param name="UpRows"></param>/// <param name="DownRows"></param>/// <param name="count"></param>private void PaintingFont(System.Windows.Forms.DataGridViewCellPaintingEventArgs e, int cellwidth, int UpRows, int DownRows, int count){SolidBrush fontBrush = new SolidBrush(e.CellStyle.ForeColor);int fontheight = (int)e.Graphics.MeasureString(e.Value.ToString(), e.CellStyle.Font).Height;int fontwidth = (int)e.Graphics.MeasureString(e.Value.ToString(), e.CellStyle.Font).Width;int cellheight = e.CellBounds.Height;if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomCenter){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y + cellheight * DownRows - fontheight);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomLeft){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y + cellheight * DownRows - fontheight);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomRight){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y + cellheight * DownRows - fontheight);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleCenter){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleLeft){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleRight){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopCenter){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1));}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopLeft){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y - cellheight * (UpRows - 1));}else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopRight){e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y - cellheight * (UpRows - 1));}else{e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);}}#endregion}
}

4.为窗体Form1添加控件(组件)HeaderUnitView:

5.控件的设置:

A、通过属性设置
(1)设置ColumnHeadersHeightSizeMode属性为:DisableResizing

(2)编辑列

(3)设置ColumnDeep属性为:2;设置CellHeight和ColumnHeadersHeight属性 (设置一个值)
(4)设置ColumnTreeView属性,添加TreeView

(5)设置ColumnTreeViewNode属性,为TreeView添加节点。

(6)设置RefreshAtHscroll属性为True。
(7)利用DataGridView方法绑定所要显示的数据即可

B、通过代码设置

 //添加列DataGridViewTextBoxColumn tcDM = newDataGridViewTextBoxColumn();tcDM.HeaderText = "班级代码";tcDM.Name = "DM";//tcDM.DataPropertyName = "DM";tcDM.ReadOnly = true;//tcDM.SortMode =DataGridViewColumnSortMode.NotSortable;//tcDM.DefaultCellStyle.Alignment =DataGridViewContentAlignment.MiddleCenter;dgv.Columns.Add(tcDM);DataGridViewTextBoxColumn tcMC = newDataGridViewTextBoxColumn();tcMC.HeaderText = "班级名称";tcMC.Name = "MC";tcMC.ReadOnly = true;dgv.Columns.Add(tcMC);DataGridViewTextBoxColumn tcNan = newDataGridViewTextBoxColumn();tcNan.HeaderText = "男";tcNan.Name = "Nan";tcNan.ReadOnly = true;dgv.Columns.Add(tcNan);DataGridViewTextBoxColumn tcNv = newDataGridViewTextBoxColumn();tcNv.HeaderText = "女";tcNv.Name = "Nv";tcNv.ReadOnly = true;dgv.Columns.Add(tcNv);//增加TreeViewTreeView tv = new TreeView();TreeNode tnDM = new TreeNode("班级代码");tv.Nodes.Add(tnDM);TreeNode tnMC = new TreeNode("班级名称");tv.Nodes.Add(tnMC);TreeNode tnSex = new TreeNode("性别");tv.Nodes.Add(tnSex);TreeNode tnNan = new TreeNode("男");tnSex.Nodes.Add(tnNan);TreeNode tnNv = new TreeNode("女");tnSex.Nodes.Add(tnNv);dgv.ColumnTreeView = new TreeView[] { tv };//设置其他属性dgv.AutoGenerateColumns =false;                                   //不自动增加列dgv.RowHeadersVisible =false;                                     //行头不可见dgv.AllowUserToAddRows = false;dgv.RowTemplate.DefaultCellStyle.Alignment =DataGridViewContentAlignment.MiddleCenter;dgv.ColumnHeadersHeightSizeMode =DataGridViewColumnHeadersHeightSizeMode.DisableResizing;dgv.ColumnDeep = 2;dgv.CellHeight = 25;dgv.ColumnHeadersHeight = 50;dgv.RefreshAtHscroll = true;

三、添加一条数据

    dgv.Rows.Add();   //添加行dgv.Rows[0].Cells["DM"].Value= "2003001";dgv.Rows[0].Cells["MC"].Value= "网络一班"; ;dgv.Rows[0].Cells["Nan"].Value= "26人";dgv.Rows[0].Cells["Nv"].Value= "18人";

四、合并单元格

headerUnitView1.MergeColumnNames.Add("Column11");//Column11需要合并单元格的列

如果有三层表头就把ColumnDeep改成3,,依次...

转载于:https://www.cnblogs.com/ss0xt/p/6667185.html

C#中Winform程序中如何实现多维表头【不通过第三方报表程序】相关推荐

  1. 微信小程序使用canvas绘制二维码实现跳转小程序

    开始接到这个需求的时候,我查阅文档获取小程序码 | 微信开放文档 发现两种途径 需要后端在服务器上调用接口拿到二维码,因为调用的 https://api.weixin.qq.com这个域名是不允许上白 ...

  2. uniapp 微信小程序长按识别二维码,跳转小程序、个人微信

    前言: 业务要求是小程序放一个二维码图片,长按可以识别二维码,进而识别出个人微信,添加个人微信:我们可以通过uni.previewImage(OBJECT)或者wx.previewImage(Obje ...

  3. 在winform程序中启动wpf窗体

    有时候需要在winform程序中利用wpf的许多优良特性,如何在其中启动wpf窗体呢? 前提:MainWindow.xaml是从别的地方copy到这个项目的,值得注意的是,除了MainWindow.x ...

  4. 在WinForm应用程序中嵌入WPF控件(转)

      我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是 ...

  5. 转:WinForm程序中两份mdf文件问题的解决方法

    在项目中用程序中嵌入mdf文件的方式来进行SQLServer数据库开发非常方便,用来发布开源项目等很方便,点击就可以运行,免部署,特别是在教学中用起来更加方便,老师不用先将数据库文件detach再发给 ...

  6. winform关闭当前form_C#中WinForm程序退出方法技巧总结

    C#中WinForm程序退出方法技巧总结 一.关闭窗体 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.Ex ...

  7. 在WinForm程序中嵌入ASP.NET

    现在的流行趋势是桌面程序Web化,Web程序桌面化,呵呵.最终目标就是你中有我,我中有你.例如MSN Explorer就是一个很好的展示,让用户在使用的时候分不清什么时候是在本地什么时候是在网络.而这 ...

  8. 在Winform程序中设置管理员权限及为用户组添加写入权限

    在我们一些Winform程序中,往往需要具有一些特殊的权限才能操作系统文件,我们可以设置运行程序具有管理员权限或者设置运行程序的目录具有写入的权限,如果是在操作系统里面,我们可以设置运行程序以管理员身 ...

  9. 在WinForm程序中嵌入ASP.NET[转]

    在WinForm程序中嵌入ASP.NET 现在的流行趋势是桌面程序Web化,Web程序桌面化,呵呵.最终目标就是你中有我,我中有你.例如MSN Explorer就是一个很好的展示,让用户在使用的时候分 ...

最新文章

  1. OSPF-lsa-types
  2. k8s通过label来控制pod的位置
  3. python字符串讲解
  4. 使用ABAP调用BRF+ function
  5. JS高级:事件冒泡和事件捕获;
  6. 50 MM配置-库存管理和实际库存-自动建立库存地点
  7. html页面上使用vlc,【JSJQuery】使用VLC在html中播放rtsp视频
  8. Mac下安装Flink的local模式(flink-1.0.2)
  9. arcgis怎么只显示一个图斑_森林监测、图斑核查必备技能
  10. mysql建用户注册登录表_登录注册数据库建立
  11. MATLAB显示图像为什么一片白
  12. 【Matlab】在Simulink中仿真Park变换
  13. 基于Revel开发的组件化代码生成器
  14. 一些常用意大利语 1000个单词
  15. 创业公司的抗争,共享单车的合并
  16. ppt循环动画的制作
  17. 2012年中国本土IC设计企业排名TOP10
  18. Set接口下的三个实用类
  19. 2022.11.15【bug笔记】|Error in FASTQ file at line 55: Line expected to start with ‘+‘, but found ‘G‘
  20. 双 JK 触发器 74LS112 逻辑功能。真值表_触发器的工作原理是什么

热门文章

  1. centos7samba服务的搭建
  2. GeneratorSqlMapCustom(mybatis逆向工程)
  3. Swift与LLVM-Clang原理与示例
  4. Lidar激光雷达市场
  5. MindSpore算子支持类
  6. 自动调度GPU的卷积层
  7. 处理器解决物联网和人工智能的融合
  8. Glide执行流程总结
  9. LookupError: unknown encoding: uft-8
  10. python 创建.txt的文件 并写内容到里面