• DataGridView的复合表头


    本实现方法为网上流传最广的方法,本人做了一些修改,修正一些可能出现的BUG.

    下面是自定义控件源码:

    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 MultiHeaderDataGridView
    {
    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;

            /// <summary>
    /// 构造函数
    /// </summary>
    public HeaderUnitView()
    {
    InitializeComponent();
    this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
    //设置列高度显示模式           
    }

            [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);
    ////写字段文本
    ////Brush brush=new SolidBrush(e.CellStyle.ForeColor);           

    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)
    {
    base.OnScroll(e);
    //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) + 1;               
    }
    base.OnColumnWidthChanged(e);
    //this.Refresh();
    }

    /// <summary>
    /// 单元格绘制(重写)
    /// </summary>
    /// <param name="e"></param>
    /// <remarks></remarks>
    protected override void OnCellPainting(System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
    {
    try
    {
    //行标题不重写
    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; }                   
    Application.DoEvents();
    PaintUnitHeader((TreeNode)NadirColumnList[e.ColumnIndex]
    , e
    , _columnDeep);
    e.Handled = true;
    }
    }
    catch
    { }
    }        
    }
    }

    生成些控件方法:

    private MultiHeaderDataGridView.HeaderUnitView createDataGridView()

    {

    MultiHeaderDataGridView.HeaderUnitView dgv=new MultiHeaderDataGridView.HeaderUnitView();

    TreeView treeview = new TreeView();//生成一个树

    TreeNode tn = new TreeNode();

    tn.Text = "node1"; treeview.Nodes.Add(tn); tn = new TreeNode(); tn.Text = "node2"; treeview.Nodes[0].Nodes.Add(tn);

    tn = new TreeNode(); tn.Text = "node3"; treeview.Nodes[0].Nodes.Add(tn);

    dgv.Columns.Add("column1");//添加列   

    dgv.Columns.Add("column2");//添加列   

    dgv.ColumnTreeView = new TreeView[] { treeview };
    dgv.ColumnDeep = 2;//列深
    dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    dgv.AutoGenerateColumns = false;                                    //不自动增加列
    dgv.RowHeadersVisible = false;                                      //行头不可见

    }

    这样就可以生成一个一个大列下有二个小列的表.......复杂的表头同样的源理.

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

  • 相关阅读:
    在github上用octopress搭建博客过程纪要
    各自用一句话来概括MVC、MVP、MVVM的差异特点
    二级域名使用下划线
    knockout.js的学习笔记2
    knockout.js的学习笔记
    knockout.js的学习笔记4
    利用GitHub Pages安装部署Octopress博客
    安装.net framework 4.0失败,出现HRESULT 0xc8000222错误代码
    版本控制工具GitHub发布Windows版
    C#多线程中 lock用法
  • 原文地址:https://www.cnblogs.com/605395451/p/2153842.html
Copyright © 2020-2023  润新知