DataGridView扩展功能 多行列头、合并单元格

http://blog.sina.com.cn/s/blog_63160fa801014ity.html

 public partial class ExtDataGridView : DataGridView
{
#region 变量、属性
/// <summary>
/// 列头信息树
/// </summary>
private TreeView _columnTreeView = null;
/// <summary>
/// DataGirdView列
/// </summary>
private ArrayList _columnList = new ArrayList();
/// <summary>
/// 单元格高度
/// </summary>
private int _cellHeight = 17;
/// <summary>
/// 获取或设置单元格高度
/// </summary>
public int CellHeight
{
get { return _cellHeight; }
set { _cellHeight = value; }
}
private List<string> _mergecolumnname = new List<string>();
/// <summary>
/// 列头层数
/// </summary>
private int _columnDeep = 1;
/// <summary>
/// 滚动时刷新
/// </summary>
private bool _hscrollRefresh = false;
/// <summary>
/// 水平滚动时是否刷新表头,数据较多时可能会闪烁,不刷新时可能显示错误
/// </summary>
[Description("水平滚动时是否刷新表头,数据较多时可能会闪烁,不刷新时可能显示错误")]
public bool RefreshAtHscroll
{
get { return _hscrollRefresh; }
set { _hscrollRefresh = value; }
}
[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
{
_columnTreeView = value;
}
}
[Description("设置添加的字段树的相关属性")]
public TreeView ColumnTreeViewNode
{
get
{
if (_columnTreeView == null)
return null;
return _columnTreeView;
}
}
/// <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;
}
}
/// <summary>
/// 获取列头数中的实际列头
/// </summary>
public ArrayList NadirColumnList
{
get
{
if (_columnTreeView == null)
return null;
//if (_columnTreeView[0] == null)
//    return null;
if (_columnTreeView.Nodes == null)
return null;
if (_columnTreeView.Nodes.Count == 0)
return null;
_columnList.Clear();
GetNadirColumnNodes(_columnList, _columnTreeView.Nodes[0], false);
return _columnList;
}
}
#endregion
#region 构造函数
/// <summary>
/// 创建DataGridView默认实例
/// </summary>
public ExtDataGridView()
{
InitializeComponent();
this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
//设置列高度显示模式
//表头居中对齐
base.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
//将列填充整个DataGrid
//base.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
#endregion
#region 列头
///<summary>
///绘制合并表头
///</summary>
///<param name="node">合并表头节点</param>
///<param name="e">绘图参数集</param>
///<param name="level">结点深度</param>
///<remarks></remarks>
public void PaintUnitHeader(TreeNode node, 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;
int index = 0;
//获得最底层字段的宽度
if (node.Nodes == null || node.Nodes.Count == 0)
{
index = GetColumnListNodeIndex(node);
if (this.Columns.Count > index)
return this.Columns[index].Width;
else
return uhWidth;
}
//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;
}
}
}
}
#endregion
#region 重写方法
/// <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 && MergeColumnNames.Count > 0)
{
MergeCell(e);
}
else if (_columnTreeView != null && _columnTreeView.Nodes.Count > 0)
{
//行标题不重写
if (e.ColumnIndex < 0)
{
base.OnCellPainting(e);
return;
}
if (_columnDeep == 1)
{
base.OnCellPainting(e);
return;
}
//绘制表头
if (e.RowIndex == -1 && NadirColumnList != null)
{
if (e.ColumnIndex >= NadirColumnList.Count) { e.Handled = true; return; }
PaintUnitHeader((TreeNode)NadirColumnList[e.ColumnIndex]
, e
, _columnDeep);
e.Handled = true;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <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); }
if (MergeColumnNames.Count > 0 ||
(_columnTreeView != null && _columnTreeView.Nodes.Count > 0))
{
this.Refresh();
}
base.OnColumnWidthChanged(e);
}
/// <summary>
/// 值变更时刷新
/// </summary>
/// <param name="e"></param>
protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
{
string colName = this.Columns[e.ColumnIndex].Name;
if (this.MergeColumnNames.Contains(colName))
this.Refresh();
base.OnCellValueChanged(e);
}
#endregion
#region 合并单元格
/// <summary>
/// 画单元格
/// </summary>
/// <param name="e"></param>
private void MergeCell(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 != null && 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 != null &&
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;
}
}
#endregion
count = 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);
if (e.RowIndex == this.Rows.Count - 1)
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
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 == null ? string.Empty : e.Value.ToString(), e.CellStyle.Font).Height;
int fontwidth = (int)e.Graphics.MeasureString(e.Value == null ? string.Empty : 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
private void InitializeComponent()
{
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
this.SuspendLayout();
//
// HeaderUnitView
//
this.RowTemplate.Height = 23;
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
this.ResumeLayout(false);
}
}

DataGridView 多层列头、合并单元格相关推荐

  1. C# Excel 行高,列宽,合并单元格,单元格边框线,冻结

    C# Excel 行高,列宽,合并单元格,单元格边框线,冻结 原文:http://hi.baidu.com/kjkj911/blog/item/0ecc3ec7855dd6d4d100600f.htm ...

  2. C# Excel 行高,列宽,合并单元格,单元格边框线,冻结(转载) - 关于C#操作EXCLE常见操作比较全的

    网上看到的比较全的关于C#操作EXCEL常见操作集合,比较全,写的不错 原文地址:http://hi.baidu.com/kjkj911/blog/item/0ecc3ec7855dd6d4d1006 ...

  3. 【Excel / WPS表格】如何按列进行合并单元格?或者说按行进行合并单元格?

    一.问题背景 有时候我们需要把n排m列的单元格合并成n排或者合并成m列,但是excel本身并没有这种直观明显的操作/功能按钮. wps表格中有一个按行合并的功能,能将n排m列的单元格合并成n排. 但是 ...

  4. Excel列上不等合并单元格一键输入连续序号操作

    今天小编要分享的是,Excel不等的合并单元格也可以一键输入连续的序号操作,如下图所示.需要在第一列.合并单元格输入连续的序号. (方方格子插件) 1.先看动图演示吧 2.在开始操作之前我们需要先选择 ...

  5. EasyExcel合并单元格(同列相同数据合并)

    合并后效果如下: 合并策略代码: public class CustomMergeStrategy extends AbstractMergeStrategy {/*** 分组,每几行合并一次*/pr ...

  6. python在excel表里如何新增一列或者一行?新增之后,公式和合并单元格会怎样变化?

    首先导入openpyxl库,即: import openpyxl as op 然后打开你已有的excel,即: wb=op.open('新增一列.xlsx')#打开新增一列.xlsx这个工作簿 ws= ...

  7. java excel导出 jxl_java使用JXL导出Excel及合并单元格

    jxl是一个韩国人写的java操作excel的工具,在开源世界中,有两套比较有影响的API可供使用,一个是POI,一个是jExcelAPI.其中功能相对POI比较弱一点.但jExcelAPI对中文支持 ...

  8. 在合并单元格中数组公式无效_Excel中合并单元格困扰多年的难题,终于被我搞定了...

    Excel表格中如果存在合并单元格,经常会遇到一些问题,比如序号填充.数据统计或筛选等,如下图所示,需要根据指定人员姓名查找引用对应的销售部门和销售金额. 这个问题关键在于销售部门列存在合并单元格,如 ...

  9. Markdown编辑表格实现合并单元格、单元格内容换行

    Markdown虽然没有合并单元格的语法,但是Markdown是兼容HTML的,因此,我们可以通过HTML的方式实现单元格合并. 跨行合并使用 rowspan 属性 跨列合并使用 colspan 属性 ...

最新文章

  1. 第十六周程序阅读(7)
  2. Lintcode 569解题思路及c++代码
  3. log4日志内容换行_Linux 下 4 种实时监控日志文件的方法,总有一种适合你
  4. WIF基本原理(2)基于声明的标识模型
  5. 最佳买卖股票时机含冷冻期
  6. python可迭代对象 迭代器生成器_Python可迭代对象、迭代器和生成器
  7. Java多线程干货系列(1):Java多线程基础
  8. linux查看vnc进程命令_linux命令:VNC服务的配置及使用
  9. Troubleshooting OpenStack 瘫痪 - 每天5分钟玩转 OpenStack(160)
  10. [转载] 的士速递3
  11. datetime只要年月python_Python 的日期和时间处理
  12. SQL Server 不允许保存更改的解决方法
  13. 百度生成短链接(Get请求方式)
  14. 学phyton第二天
  15. 傅里叶变换之掐死教程(完整版)
  16. 网管、桌面运维、技术支持 有出路吗
  17. 第三章 分布式扩展(一)
  18. 【量化课程】01_投资与量化投资
  19. Windows上解除宽带限速(网速明显提升)
  20. 百度 oppo 滴滴出行 面试问题总结 阿里

热门文章

  1. C# CRC16数据校验支持ModelBus和XMODEM校验模式
  2. 富士康回击 爆黑幕记者资产遭法院冻结
  3. nmake fatal error U1007:‘#’
  4. 如何区分高压和低压电阻接地系统
  5. prometheus+node_exporter+grafana+alertManager+prometheus-webhook-dingtalk实现服务器监控显示,钉钉机器人告警消息通知
  6. Prescan问题及处理办法汇总
  7. 图像拼接算法总结(二)
  8. 英语魔法师之语法俱乐部 | 笔记6 | 初级句型—简单句 | Chapter5—动名词
  9. 【毕业设计】大数据网络舆情热点分析系统 - python 情感分析
  10. 四舍六入五凑偶”的修约规则进行修约