Datagridview 实现二维表头和行合并

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

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

你可能感兴趣的:(datagridview)