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


    问题: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;
                            }
                        }
                        #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);
    
                    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)设置ColumnHeadersHeightSizeM
    ode属性为: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);
     //增加TreeView
     TreeView 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,,依次...




    http://huangxiutao.cn
  • 相关阅读:
    Django -- 10.Django和Ajax
    Django -- 9.模型层(2)
    Django -- 8.模型层(1)
    Django -- 7.模板层
    Django -- 6.视图层
    Django -- 5.路由层(URLconf)_基于Django2
    Django -- 4.Django简介
    Django -- 3.web框架
    Delphi中Chrome Chromium、Cef3学习笔记(四)
    Delphi中Chrome Chromium、Cef3学习笔记(三)
  • 原文地址:https://www.cnblogs.com/ss0xt/p/6667185.html
Copyright © 2020-2023  润新知