自定义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
相关产品推荐
相关产品推荐

