You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#的DataGridView单元格中同时添加文本与图像?

实现带行列号表头及图文混合单元格的DataGridView

针对你的需求,不需要拆分行来实现图文显示,通过自定义DataGridView单元格和表头自定义绘制就能完美解决,既保持原有行列数量,又能实现所有要求的功能。

一、核心思路

  1. 表头行列号:通过自定义列头单元格绘制列号,利用行的RowPostPaint事件绘制行号,不修改原有表头结构。
  2. 图文混合单元格:自定义DataGridViewCell,重写Paint方法手动绘制文本(上方)和图像(下方),完全控制布局,无需调整行列数量。

二、具体实现代码(C# WinForms)

1. 自定义图文单元格与列

// 自定义支持文本+图像的单元格,文本在图像上方
public class ImageTextCell : DataGridViewTextBoxCell
{
    protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
    {
        // 先绘制单元格基础样式(背景、边框等),跳过默认文本绘制
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.ContentForeground);

        // 解析单元格数据:假设数据是文本+图像的键值对(也可替换为自定义实体类)
        if (value is KeyValuePair<string, Image> data)
        {
            string text = data.Key;
            Image image = data.Value;

            // 绘制文本:居中,顶部留5px间距
            SizeF textSize = graphics.MeasureString(text, cellStyle.Font);
            PointF textPos = new PointF(
                cellBounds.Left + (cellBounds.Width - textSize.Width) / 2,
                cellBounds.Top + 5
            );
            using (var textBrush = new SolidBrush(cellStyle.ForeColor))
            {
                graphics.DrawString(text, cellStyle.Font, textBrush, textPos);
            }

            // 绘制图像:居中,在文本下方留5px间距
            if (image != null)
            {
                int imageTop = (int)(textPos.Y + textSize.Height + 5);
                int imageLeft = cellBounds.Left + (cellBounds.Width - image.Width) / 2;
                Rectangle imageRect = new Rectangle(imageLeft, imageTop, image.Width, image.Height);
                // 确保图像不超出单元格范围
                imageRect.Intersect(cellBounds);
                graphics.DrawImage(image, imageRect);
            }
        }
    }
}

// 自定义列,绑定上面的图文单元格
public class ImageTextColumn : DataGridViewColumn
{
    public ImageTextColumn() : base(new ImageTextCell())
    {
        Width = 120; // 设置默认列宽,适配图文显示
    }

    public override DataGridViewCell CellTemplate
    {
        get => base.CellTemplate;
        set
        {
            if (value != null && !(value is ImageTextCell))
                throw new InvalidCastException("必须使用ImageTextCell作为单元格模板");
            base.CellTemplate = value;
        }
    }
}

2. 实现表头行列号与DataGridView配置

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
        ConfigureDataGridView();
        LoadTestData();
    }

    private void ConfigureDataGridView()
    {
        var grid = dataGridView1;
        grid.RowHeadersWidth = 60; // 扩大行头宽度,容纳行号
        grid.ColumnHeadersHeight = 40; // 扩大列头高度,同时显示列号和列名
        grid.RowTemplate.Height = 100; // 设置行高,足够显示图文

        // 添加自定义图文列
        for (int i = 0; i < 3; i++)
        {
            var col = new ImageTextColumn();
            col.Name = $"Column{i+1}";
            col.HeaderText = $"分类{i+1}";
            grid.Columns.Add(col);
        }

        // 绑定行号绘制事件
        grid.RowPostPaint += Grid_RowPostPaint;
        // 设置自定义列头单元格,显示列号
        grid.ColumnHeaderCellTemplate = new NumberedColumnHeaderCell();
    }

    // 绘制行号(行索引+1)
    private void Grid_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
    {
        var grid = sender as DataGridView;
        string rowNum = (e.RowIndex + 1).ToString();
        var font = new Font(grid.Font.FontFamily, 10, FontStyle.Bold);
        using (var brush = new SolidBrush(grid.RowHeadersDefaultCellStyle.ForeColor))
        {
            SizeF textSize = e.Graphics.MeasureString(rowNum, font);
            // 行号居中显示
            float x = grid.RowHeadersWidth / 2 - textSize.Width / 2;
            float y = e.RowBounds.Top + (e.RowBounds.Height - textSize.Height) / 2;
            e.Graphics.DrawString(rowNum, font, brush, x, y);
        }
    }

    // 加载测试数据(替换为你自己的文本+图像数据)
    private void LoadTestData()
    {
        var grid = dataGridView1;
        for (int i = 0; i < 5; i++)
        {
            var rowData = new object[grid.Columns.Count];
            for (int j = 0; j < grid.Columns.Count; j++)
            {
                // 示例数据:文本对应图像
                string text = j switch { 0 => "dog", 1 => "cat", _ => "bird" };
                Image img = j switch { 0 => Properties.Resources.Dog, 1 => Properties.Resources.Cat, _ => Properties.Resources.Bird };
                rowData[j] = new KeyValuePair<string, Image>(text, img);
            }
            grid.Rows.Add(rowData);
        }
    }
}

// 自定义列头单元格,显示列号+列名
public class NumberedColumnHeaderCell : DataGridViewColumnHeaderCell
{
    protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
    {
        // 先绘制默认列头样式,跳过默认文本绘制
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.ContentForeground);

        string colNum = (OwningColumn.Index + 1).ToString();
        var boldFont = new Font(cellStyle.Font.FontFamily, 10, FontStyle.Bold);
        using (var brush = new SolidBrush(cellStyle.ForeColor))
        {
            // 绘制列号在左上角
            graphics.DrawString(colNum, boldFont, brush, cellBounds.Left + 5, cellBounds.Top + 5);
            // 绘制列名在下方居中
            SizeF textSize = graphics.MeasureString(formattedValue.ToString(), cellStyle.Font);
            PointF textPos = new PointF(
                cellBounds.Left + (cellBounds.Width - textSize.Width) / 2,
                cellBounds.Top + 25
            );
            graphics.DrawString(formattedValue.ToString(), cellStyle.Font, brush, textPos);
        }
    }
}

三、关键说明

  • 无行列数量变化:所有自定义逻辑都在单元格和表头的绘制层面实现,不会增加或修改原有行列结构。
  • 布局可控:文本和图像的位置、间距都可以通过调整坐标参数自定义。
  • 数据兼容性:可以将KeyValuePair替换为你自己的实体类(比如包含Text和Image属性的类),只需在Paint方法中对应解析即可。

内容的提问来源于stack exchange,提问作者Bha01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:15:41