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

自定义DataGridViewColumn图片复选框列绘制问题求助

自定义DataGridView图片复选框列问题修复

问题描述

我尝试创建自定义DataGridViewColumn,用图片实现现代风格的复选框列,已将选中和未选中状态的PNG图片存入资源(可通过Resources.CheckedBox和Resources.UncheckedBox访问),该列仅需显示图片无需文本。目前遇到两个问题:

  • 拖动调整列宽时,单元格无法正确重绘,UI出现错乱
  • 点击单元格时,无法根据状态切换对应图片

现有代码

public class CustomDataGridColumn : DataGridViewColumn
{
    public CustomDataGridColumn()
    {
        this.CellTemplate = new CustomDataGridCell();
    }
}

public class CustomDataGridCell : DataGridViewCell
{
    private static Image img = Resources.UncheckedBox;
    public bool Checked { get; set; }

    public CustomDataGridCell()
    {
        Checked = false;
    }
    protected override object GetFormattedValue(object value,
        int rowIndex, ref DataGridViewCellStyle cellStyle,
        TypeConverter valueTypeConverter,
        TypeConverter formattedValueTypeConverter,
        DataGridViewDataErrorContexts context)
    {
        return img;
    }

    protected override void OnClick(DataGridViewCellEventArgs e)
    {
        if (Checked)
        {
            Checked = false;
            //Change the image to Resource.UncheckedBox;
        }
        else
        {
            Checked = true;
            //Change the image to Resource.CheckedBox;
        }
        base.OnClick(e);
    }

    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);

        graphics.DrawImage(Resources.CheckedBox, new Point(cellBounds.Width/2, cellBounds.Y));
    }
}

问题分析

现有代码存在以下核心问题:

  • img为静态字段,所有单元格共享同一实例,导致单个单元格状态变化时全局同步
  • Paint方法固定绘制选中状态图片,未关联当前单元格的Checked状态
  • 点击切换状态后未触发单元格重绘,UI无法实时更新
  • 图片绘制位置计算错误,未考虑单元格高度和列宽变化,导致拖动列宽时偏移错乱
  • GetFormattedValue返回静态图片,与单元格实际状态脱节

修复后代码

public class CustomDataGridColumn : DataGridViewColumn
{
    public CustomDataGridColumn()
    {
        CellTemplate = new CustomDataGridCell();
        // 初始化列宽适配图片,预留边距
        Width = Resources.CheckedBox.Width + 8;
    }
}

public class CustomDataGridCell : DataGridViewCell
{
    public bool Checked { get; set; }

    public CustomDataGridCell()
    {
        Checked = false;
        // 设置单元格内容居中对齐
        Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
    }

    protected override object GetFormattedValue(object value,
        int rowIndex, ref DataGridViewCellStyle cellStyle,
        TypeConverter valueTypeConverter,
        TypeConverter formattedValueTypeConverter,
        DataGridViewDataErrorContexts context)
    {
        // 返回空字符串,避免默认文本绘制
        return string.Empty;
    }

    protected override void OnClick(DataGridViewCellEventArgs e)
    {
        // 切换选中状态
        Checked = !Checked;
        // 触发单元格重绘,更新UI
        DataGridView?.InvalidateCell(this);
        base.OnClick(e);
    }

    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);

        // 根据当前状态选择对应图片
        Image displayImage = Checked ? Resources.CheckedBox : Resources.UncheckedBox;
        if (displayImage == null) return;

        // 计算图片居中位置,适配任意单元格大小
        int imageX = cellBounds.Left + (cellBounds.Width - displayImage.Width) / 2;
        int imageY = cellBounds.Top + (cellBounds.Height - displayImage.Height) / 2;

        // 绘制图片到单元格内
        graphics.DrawImage(displayImage, new Point(imageX, imageY));
    }
}

关键修复点

  • 移除静态img字段,每个单元格独立维护Checked状态,实现单格独立控制
  • Paint方法动态根据Checked状态切换图片,同时计算居中坐标,适配列宽/行高变化
  • 点击事件中调用InvalidateCell触发重绘,确保UI实时响应状态变化
  • 禁用默认文本绘制,避免图片与文本重叠
  • 初始化列宽适配图片尺寸,优化初始显示效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:05:21