• Datagridview 实现二维表头和行合并


        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Drawing;
        using System.Drawing.Design;
        using System.Windows.Forms;
    
        /// <summary>
        /// DataGridView行合并.请对属性MergeColumnNames 赋值既可
        /// </summary>
        public partial class RowMergeView : DataGridView
        {
            #region 构造函数
            public RowMergeView()
            {
                SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
                UpdateStyles();
                InitializeComponent();
            }
            #endregion
            #region 重写的事件
            protected override void OnPaint(PaintEventArgs pe)
            {
                // TODO: 在此处添加自定义绘制代码
    
                // 调用基类 OnPaint
                base.OnPaint(pe);
            }
            protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
            {
                try
                {
                    if (e.RowIndex > -1 && e.ColumnIndex > -1)
                    {
                        DrawCell(e);
                    }
                    else
                    {
                        //二维表头
                        if (e.RowIndex == -1)
                        {
                            if (SpanRows.ContainsKey(e.ColumnIndex)) //被合并的列
                            {
                                //画边框
                                Graphics g = e.Graphics;
                                e.Paint(e.CellBounds, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
    
                                int left = e.CellBounds.Left, top = e.CellBounds.Top + 2,
                                right = e.CellBounds.Right, bottom = e.CellBounds.Bottom;
    
                                switch (SpanRows[e.ColumnIndex].Position)
                                {
                                    case 1:
                                        left += 2;
                                        break;
                                    case 2:
                                        break;
                                    case 3:
                                        right -= 2;
                                        break;
                                }
    
                                //画上半部分底色
                                g.FillRectangle(new SolidBrush(this._mergecolumnheaderbackcolor), left, top,
                                right - left, (bottom - top) / 2);
    
                                //画中线
                                g.DrawLine(new Pen(this.GridColor), left, (top + bottom) / 2,
                                right, (top + bottom) / 2);
    
                                //写小标题
                                var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
    
                                g.DrawString(e.Value + "", e.CellStyle.Font, Brushes.Black,
                                new Rectangle(left, (top + bottom) / 2, right - left, (bottom - top) / 2), sf);
                                left = this.GetColumnDisplayRectangle(SpanRows[e.ColumnIndex].Left, true).Left - 2;
    
                                if (left < 0) left = this.GetCellDisplayRectangle(-1, -1, true).Width;
                                right = this.GetColumnDisplayRectangle(SpanRows[e.ColumnIndex].Right, true).Right - 2;
                                if (right < 0) right = this.Width;
    
                                g.DrawString(SpanRows[e.ColumnIndex].Text, e.CellStyle.Font, Brushes.Black,
                                new Rectangle(left, top, right - left, (bottom - top) / 2), sf);
                                e.Handled = true;
                            }
                        }
                    }
                    base.OnCellPainting(e);
                }
                catch
                { }
            }
    
            protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e)
            {
                if (this.RowHeadersVisible)
                {
                    var rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, this.RowHeadersWidth - 4, e.RowBounds.Height);
    
                    TextRenderer.DrawText(e.Graphics,
                        (e.RowIndex + 1).ToString(),
                        this.RowHeadersDefaultCellStyle.Font,
                        rectangle,
                        this.RowHeadersDefaultCellStyle.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
                }
    
                base.OnRowPostPaint(e);
            }
    
            protected override void OnScroll(ScrollEventArgs e)
            {
                if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)// && e.Type == ScrollEventType.EndScroll)
                {
                    timer1.Enabled = false;
                    timer1.Enabled = true;
                }
            }
    
            #endregion
            #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);
                var backBrush = new SolidBrush(e.CellStyle.BackColor);
                var fontBrush = new SolidBrush(e.CellStyle.ForeColor);
                //上面相同的行数
                int UpRows = 0;
                //下面相同的行数
                int DownRows = 0;
                //总行数
                int count = 0;
                if (this.MergeColumnNames.Contains(this.Columns[e.ColumnIndex].Name) && e.RowIndex != -1)
                {
                    int cellwidth = e.CellBounds.Width;
                    var 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)
            {
                var fontBrush = new SolidBrush(e.CellStyle.ForeColor);
                var fontheight = (int)e.Graphics.MeasureString(e.Value.ToString(), e.CellStyle.Font).Height;
                var 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
            #region 属性
            /// <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>();
            #endregion
            #region 二维表头
            private struct SpanInfo //表头信息
            {
                public SpanInfo(string Text, int Position, int Left, int Right)
                {
                    this.Text = Text;
                    this.Position = Position;
                    this.Left = Left;
                    this.Right = Right;
                }
    
                public readonly string Text; //列主标题
                public readonly int Position; //位置,1:左,2中,3右
                public readonly int Left; //对应左行
                public readonly int Right; //对应右行
            }
            private readonly Dictionary<int, SpanInfo> SpanRows = new Dictionary<int, SpanInfo>();//需要2维表头的列
            /// <summary>
            /// 合并列
            /// </summary>
            /// <param name="ColIndex">列的索引</param>
            /// <param name="ColCount">需要合并的列数</param>
            /// <param name="Text">合并列后的文本</param>
            public void AddSpanHeader(int ColIndex, int ColCount, string Text)
            {
                if (ColCount < 2)
                {
                    throw new Exception("行宽应大于等于2,合并1列无意义。");
                }
                //将这些列加入列表
                int Right = ColIndex + ColCount - 1; //同一大标题下的最后一列的索引
                SpanRows[ColIndex] = new SpanInfo(Text, 1, ColIndex, Right); //添加标题下的最左列
                SpanRows[Right] = new SpanInfo(Text, 3, ColIndex, Right); //添加该标题下的最右列
                for (int i = ColIndex + 1; i < Right; i++) //中间的列
                {
                    SpanRows[i] = new SpanInfo(Text, 2, ColIndex, Right);
                }
            }
            /// <summary>
            /// 清除合并的列
            /// </summary>
            public void ClearSpanInfo()
            {
                SpanRows.Clear();
                //ReDrawHead();
            }
    
            //刷新显示表头
            public void ReDrawHead()
            {
                foreach (int si in SpanRows.Keys)
                {
                    this.Invalidate(this.GetCellDisplayRectangle(si - 1, -1, true));
                }
            }
            private void timer1_Tick(object sender, EventArgs e)
            {
                timer1.Enabled = false;
                ReDrawHead();
            }
            /// <summary>
            /// 二维表头的背景颜色
            /// </summary>
            [Description("二维表头的背景颜色"), Browsable(true), Category("二维表头")]
            public Color MergeColumnHeaderBackColor
            {
                get { return this._mergecolumnheaderbackcolor; }
                set { this._mergecolumnheaderbackcolor = value; }
            }
            private Color _mergecolumnheaderbackcolor = System.Drawing.SystemColors.Control;
            #endregion
        }
    

      需要新建一个组件类,拖放一个timer,你也可以不使用timer,直接把timer里面的方法放到调用的地方

    使用:

           DataTable dt = new DataTable();
                dt.Columns.Add("1");
                dt.Columns.Add("2");
                dt.Columns.Add("3");
                dt.Columns.Add("4");
                dt.Rows.Add("中国", "上海", "5000", "7000");
                dt.Rows.Add("中国", "北京", "3000", "5600");
                dt.Rows.Add("美国", "纽约", "6000", "8600");
                dt.Rows.Add("美国", "华劢顿", "8000", "9000");
                dt.Rows.Add("英国", "伦敦", "7000", "8800");
                this.rowMergeView1.DataSource = dt;
                this.rowMergeView1.ColumnHeadersHeight = 40;
                this.rowMergeView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
                this.rowMergeView1.MergeColumnNames.Add("Column1");
                this.rowMergeView1.AddSpanHeader(2, 2, "XXXX");
    

      PS:http://www.cnblogs.com/greatverve/archive/2012/03/05/multi-datagridview.html

    缺点:只能二维,不能多维

  • 相关阅读:
    ASP.NET MVC案例——————拦截器
    Windows Azure Virtual Network (10) 使用Azure Access Control List(ACL)设置客户端访问权限
    Windows Azure Storage (20) 使用Azure File实现共享文件夹
    Windows Azure HandBook (5) Azure混合云解决方案
    Windows Azure Service Bus (6) 中继(Relay On) 使用VS2013开发Service Bus Relay On
    Azure PowerShell (9) 使用PowerShell导出订阅下所有的Azure VM的Public IP和Private IP
    Windows Azure Service Bus (5) 主题(Topic) 使用VS2013开发Service Bus Topic
    Azure China (9) 在Azure China配置CDN服务
    Windows Azure Storage (19) 再谈Azure Block Blob和Page Blob
    Windows Azure HandBook (4) 分析Windows Azure如何处理Session
  • 原文地址:https://www.cnblogs.com/tewuapple/p/2671560.html
Copyright © 2020-2023  润新知