如何在 Windows Forms DataGridView 单元格中托管颜色选择器组合框
一篇关于如何向 DataGridView 添加颜色选择器 ComboBox 的文章。

引言
.NET Framework 为 WinForms 开发提供了相当丰富的 UI 控件和组件。但是,有一个特别的控件一直缺失。我说的是一个具有下拉颜色选择功能的颜色选择器控件,就像 Visual Studio .NET 属性浏览器中用于编辑 Color 类型属性的那个。
Palo Mraz 开发了一个颜色选择器控件,并在此网站上发布。我想在 DataGridView
中使用这个控件,但我找不到任何相关的示例。唯一可用的关于如何在 DataGridView
中使用自定义控件的示例都与文本控件有关。这个自定义控件涉及图形,而不仅仅是文本。我决定发布这篇文章,以造福其他希望在 DataGridView
中承载颜色选择器组合框的开发者。
背景
对于那些想了解颜色选择器组合框背景的读者,请参考“ColorPicker WinForms 控件”。
您可以在 这里 获取有关如何在 DataGridView
单元格中承载自定义控件的背景信息。
DataGridView 中的颜色选择器
我的项目的核心需求是在 DataGridView
中显示 WinForm 的 PropertyGrid
控件中使用的下拉颜色选择器。
DataGridView
控件提供了几个属性,您可以使用它们来调整其单元格、行和列的外观和基本行为(外观)。我的需求是显示颜色本身,旁边显示颜色的名称。
为了实现这一点,我不得不为控件实现所有者绘制,并通过创建自定义单元格、列和行来扩展其功能。
ColorPickerColumn 类
此类创建一个自定义列,用于承载一列颜色选择器单元格。它继承自 DataGridViewColumn
,并重写了 CellTemplate
属性。
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
// Ensure that the cell used for the template is a ColorPickerCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(ColorPickerCell)))
{
throw new InvalidCastException("Must be a ColorPicker");
}
base.CellTemplate = value;
}
}
ColorPickerCell 类
此类创建一个自定义单元格,用于承载颜色选择器组合框,它继承自 DataGridViewTextBoxCell
。为了以我想要的方式绘制单元格的内容,我重写了 paint
方法。
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)
{
formattedValue = null;
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
elementState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts);
Rectangle ColorBoxRect = new Rectangle();
RectangleF TextBoxRect = new RectangleF();
GetDisplayLayout(cellBounds, ref ColorBoxRect, ref TextBoxRect);
/// Draw the cell background, if specified.
if ((paintParts & DataGridViewPaintParts.Background) ==
DataGridViewPaintParts.Background)
{
SolidBrush cellBackground;
if (value != null && value.GetType() == typeof(Color))
{
cellBackground = new SolidBrush((Color)value);
}
else
{
cellBackground = new SolidBrush(cellStyle.BackColor);
}
graphics.FillRectangle(cellBackground, ColorBoxRect);
graphics.DrawRectangle(Pens.Black, ColorBoxRect);
Color lclcolor=(Color)value;
graphics.DrawString(lclcolor.Name.ToString(), cellStyle.Font,
System.Drawing.Brushes.Black, TextBoxRect);
cellBackground.Dispose();
}
}
我不得不重写的另一个方法是 ParseFormattedValue
。当用户从列表中选择自定义颜色时,他/她会获得该颜色的十六进制数字。这个数字有一个小问题:它没有添加 0x 前缀。这会导致 System.Number.StringToNumber
方法生成异常。.NET 环境尝试将此 string
转换为整数,但由于没有 0x 前缀,它无法被视为十六进制数字,因此此方法在需要时添加前缀。
public override object ParseFormattedValue
object formattedValue, DataGridViewCellStyle cellStyle,
System.ComponentModel.TypeConverter formattedValueTypeConverter,
System.ComponentModel.TypeConverter valueTypeConverter)
{
int result;
string number = "0x" + formattedValue.ToString();
if (int.TryParse(formattedValue.ToString(),
stem.Globalization.NumberStyles.HexNumber, null, out result))
//Hex number
return base.ParseFormattedValue("0x" + formattedValue.ToString(),
lStyle, formattedValueTypeConverter, valueTypeConverter);
else
return base.ParseFormattedValue(formattedValue, cellStyle,
mattedValueTypeConverter, valueTypeConverter);
}
ColorPickerControl 类
此类创建要由 ColorPickerCell
承载的自定义控件。它实现了 IDataGridViewEditingControl
接口,并重写了原始 ColorPicker
控件的 OnLeave
事件。OnLeave
– 此事件调用 NotifyDataGridViewOfValueChange
来通知 DataGridView
单元格的内容已更改。
protected override void OnLeave(EventArgs eventargs)
{
// Notify the DataGridView that the contents of the cell
// have changed.
base.OnLeave(eventargs);
NotifyDataGridViewOfValueChange();
}
Using the Code
我创建了一个名为 ExampleForm
的窗体,其中包含一个 DataGridView
控件。该网格有两个列:第一列是简单的 textbox
列,第二列是 ColorPicker
列。在此窗体中,我演示了如何将包含颜色和名称的数据加载和保存到名为 ColorData.xml 的 XML 文件中,以及如何从该文件中加载。该文件应存储在可执行文件的同一文件夹中。
历史
- 2008 年 3 月 25 日:首次发布
关于作者
我住在新西兰。过去 6 年我一直在从事 Microsoft Windows 开发。