如何在C#的DataGridViewComboBox列中为每个项设置对应颜色?
问题解答
能否将普通ComboBox添加到DataGridView后当作普通控件引用?
不行。DataGridView的列是基于单元格模板工作的:非编辑状态下,单元格是直接绘制在网格上的,并非真实控件;进入编辑状态时,会自动创建对应类型的编辑控件(比如DataGridViewComboBoxEditingControl,它是ComboBox的子类),但这个控件是网格托管的,不能像普通ComboBox那样直接全局引用和操作,必须通过自定义单元格/编辑控件的方式来扩展功能。
实现带颜色下拉项的方案
要让下拉列表的颜色名称显示对应颜色,需要同时处理编辑状态下的下拉列表绘制和非编辑状态下的单元格文本绘制,具体步骤如下:
1. 自定义编辑控件(处理下拉列表绘制)
创建继承自DataGridViewComboBoxEditingControl的类,设置手动绘制模式并绑定DrawItem事件,在事件中绘制带颜色的文本:
public class ColoredComboBoxEditingControl : DataGridViewComboBoxEditingControl { public override void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) { base.ApplyCellStyleToEditingControl(dataGridViewCellStyle); // 设置手动绘制下拉项 this.DrawMode = DrawMode.OwnerDrawFixed; this.DrawItem += ColoredComboBox_DrawItem; } private void ColoredComboBox_DrawItem(object sender, DrawItemEventArgs e) { if (e.Index < 0) return; // 绘制项的背景 e.DrawBackground(); // 获取当前项的颜色名称并转换为Color对象 string colorName = Items[e.Index].ToString(); Color itemColor = Color.FromName(colorName); // 用对应颜色绘制文本 using (Brush textBrush = new SolidBrush(itemColor)) { e.Graphics.DrawString(colorName, e.Font, textBrush, e.Bounds.X + 2, e.Bounds.Y + 2); } // 绘制焦点框 e.DrawFocusRectangle(); } }
2. 自定义单元格(处理非编辑状态绘制)
创建继承自DataGridViewComboBoxCell的类,指定使用上面的编辑控件,并重写Paint方法来绘制非编辑状态下的带颜色文本:
public class ColoredComboBoxCell : DataGridViewComboBoxCell { // 指定编辑时使用的控件类型 public override Type EditType => typeof(ColoredComboBoxEditingControl); protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { if (formattedValue != null) { // 获取选中的颜色 Color cellColor = Color.FromName(formattedValue.ToString()); // 先绘制单元格的背景、边框(排除默认文本绘制) base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.ContentForeground); // 用对应颜色绘制单元格文本 using (Brush textBrush = new SolidBrush(cellColor)) { StringFormat textFormat = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; graphics.DrawString(formattedValue.ToString(), cellStyle.Font, textBrush, cellBounds, textFormat); } } else { // 无选中值时使用默认绘制逻辑 base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); } } }
3. 自定义列(方便快速添加到DataGridView)
创建继承自DataGridViewComboBoxColumn的类,设置单元格模板为上面的自定义单元格,并预设颜色选项:
public class ColoredComboBoxColumn : DataGridViewComboBoxColumn { public ColoredComboBoxColumn() { CellTemplate = new ColoredComboBoxCell(); // 添加常用颜色名称 Items.AddRange("Red", "Green", "Blue", "Yellow", "Orange", "Purple"); } }
4. 在窗体中使用自定义列
在窗体初始化时,将自定义列添加到DataGridView即可:
public Form1() { InitializeComponent(); // 添加自定义颜色列 ColoredComboBoxColumn colorColumn = new ColoredComboBoxColumn(); colorColumn.HeaderText = "选择颜色"; dataGridView1.Columns.Add(colorColumn); // 添加一行测试数据 dataGridView1.Rows.Add(); }
关于你之前尝试的问题
你用ListViewItem添加颜色名称的方式不可行,因为DataGridViewComboBoxCell的Items集合默认会调用项的ToString()方法显示文本,而ListViewItem.ToString()返回的是"ListViewItem: {Red}"这类格式,而非纯颜色名称。正确的做法是直接添加颜色名称字符串,再通过绘制事件设置文本颜色。
内容的提问来源于stack exchange,提问作者NivGeva

