首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# DataGridView 多行表頭實現:重繪單元格繪製合併表頭效果

     編輯:程式設計綜合問答

DataGridView 默認只支持單行列標題,若需實現類似 Excel 的多行合併表頭(如主標題跨多列、子標題分列),需通過重寫 OnCellPainting 事件自定義繪製。本文提供完整實現思路與代碼。

需求分析

目標效果:

  • 第 1 行:大類標題(如「基本信息」、「成績信息」),跨多列合併
  • 第 2 行:具體列標題(如「姓名」、「語文」、「數學」)
  • 表頭固定不隨滾動,樣式美觀(邊框、背景色)

多行表頭效果圖

核心思路:隱藏默認列標題 + 繪製自定義表頭區域

  1. 設置 ColumnHeadersVisible = false 隱藏默認標題
  2. 在 Paint 事件或重寫 OnPaint 中,在控件頂部保留區域繪製兩行表頭
  3. 或使用 ColumnHeadersHeight 設置雙倍高度,在 CellPainting 中按行繪製不同內容

方案:CellPainting 事件繪製雙行表頭


private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) {
    // 僅處理列標題行
    if (e.RowIndex != -1) return;

    // 設置雙倍高度(在 Load 或構造函數中設置一次)
    // dataGridView1.ColumnHeadersHeight = 40;
    // dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

    e.PaintBackground(e.CellBounds, true);

    // 計算兩行矩形
    Rectangle topRect = new Rectangle(e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width, e.CellBounds.Height / 2);
    Rectangle bottomRect = new Rectangle(e.CellBounds.X, e.CellBounds.Y + e.CellBounds.Height / 2, e.CellBounds.Width, e.CellBounds.Height / 2);

    // 繪製上半行:大類標題(需外部映射列索引->大類)
    string topText = GetTopHeaderText(e.ColumnIndex);
    if (!string.IsNullOrEmpty(topText)) {
        TextRenderer.DrawText(e.Graphics, topText, e.CellStyle.Font, topRect, e.CellStyle.ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
        // 繪製右下邊框
        ControlPaint.DrawBorder(e.Graphics, topRect, Color.Black, ButtonBorderStyle.Solid);
    }

    // 繪製下半行:列標題
    string bottomText = dataGridView1.Columns[e.ColumnIndex].HeaderText;
    TextRenderer.DrawText(e.Graphics, bottomText, e.CellStyle.Font, bottomRect, e.CellStyle.ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
    ControlPaint.DrawBorder(e.Graphics, bottomRect, Color.Black, ButtonBorderStyle.Solid);

    e.Handled = true; // 取消默認繪製
}

輔助邏輯:列索引映射到大類


// 定義列分組:列索引 -> 大類標題
private Dictionary _topHeaders = new Dictionary {
    {0, "基本信息"}, {1, "基本信息"}, {2, "基本信息"},
    {3, "成績信息"}, {4, "成績信息"}, {5, "成績信息"}
};

private string GetTopHeaderText(int columnIndex) {
    // 僅在每組第一列顯示大類標題,或全部顯示
    return _topHeaders.ContainsKey(columnIndex) ? _topHeaders[columnIndex] : "";
}

進階:合併大類單元格(跨列無縫)

若需大類標題真正跨列合併(無內部垂直分割線),需在 Paint 事件中手動計算合併區域:


private void dataGridView1_Paint(object sender, PaintEventArgs e) {
    if (dataGridView1.ColumnHeadersHeight < 40) return;

    var groups = new[] {
        new { Start = 0, Count = 3, Title = "基本信息" },
        new { Start = 3, Count = 3, Title = "成績信息" }
    };

    foreach (var g in groups) {
        Rectangle rect = dataGridView1.GetCellDisplayRectangle(g.Start, -1, true);
        rect.Width = 0;
        for (int i = 0; i < g.Count; i++) {
            rect.Width += dataGridView1.GetCellDisplayRectangle(g.Start + i, -1, true).Width;
        }
        rect.Height = dataGridView1.ColumnHeadersHeight / 2;

        // 填充背景
        using (var brush = new SolidBrush(Color.LightGray)) e.Graphics.FillRectangle(brush, rect);
        // 繪製文本
        TextRenderer.DrawText(e.Graphics, g.Title, dataGridView1.ColumnHeadersDefaultCellStyle.Font, rect, Color.Black, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
        // 繪製外框
        ControlPaint.DrawBorder(e.Graphics, rect, Color.Black, ButtonBorderStyle.Solid);
    }
}

注意事項

  • 啟用 DoubleBuffered = true 減少閃爍
  • 滾動時表頭固定:DataGridView 原生支持列標題固定,自定義繪製區域需同步處理
  • 列寬改變時需 Invalidate() 重繪
  • 考慮使用第三方控件(如 SourceGrid、DevExpress GridControl)原生支持多行表頭
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved