如何格式化 DataGridViewComboBoxColumn 中 ComboBox 中的特定项目?

How to format a specific item in the ComboBox in a DataGridViewComboBoxColumn?

我在(重新)创建 DataGridView 中的列的方法中有与此类似的代码:

MyColumn = new DataGridViewComboBoxColumn()
{
    Name = "..",
    HeaderText = "..",
    SortMode = DataGridViewColumnSortMode.NotSortable
};       
MyColumn.Items.Clear();
foreach (string s in MyStringList)
{
    MyColumn.Items.Add(s);
}
MyColumn.Items.Add(""); 
// I would like this empty string to be shown as "No group" 
// with an italic grayed out font

我想我可能必须为列中 ComboBox-es 的项目创建一个 class,我应该在其中覆盖 ToString() 方法,但我想知道如何格式化 No Group 项。

一个相关的问题是 here,它是关于不在 DataGridView 内部的普通 ComboBox,答案是使用 DrawMode 属性和 DrawItem 事件解决问题 ComboBox class.

要自定义绘制 ComboBox,您需要处理 EditingControlShowing,然后获取 EditingControlDataGridViewComboBoxEditingControl,然后设置其 DrawMode OwnerDrawFixed 并处理其 DrawItem 事件。

要自定义绘制单元格,您需要处理 CellPainting 事件并为单元格样式设置不同的字体和颜色,让绘制继续使用新值。如果需要,您也可以绘制整个单元格。

例子

加载示例数据:

private DataTable LoadProducts()
{
    var dt = new DataTable();
    dt.Columns.Add("Name");
    dt.Columns.Add("CategoryId", typeof(int));
    dt.Rows.Add("P1", 1);
    dt.Rows.Add("P2", 1);
    dt.Rows.Add("P3", DBNull.Value);
    return dt;
}
private DataTable LoadCategories()
{
    var dt = new DataTable();
    dt.Columns.Add("Id", typeof(int));
    dt.Columns.Add("Name");
    dt.Rows.Add(DBNull.Value, "No Category");
    dt.Rows.Add(1, "C1");
    dt.Rows.Add(2, "C2");
    dt.Rows.Add(2, "C3");
    return dt;
}

设置 DataGridView 列:

private void Form1_Load(object sender, EventArgs e)
{
    var products = LoadProducts();
    var categories = LoadCategories();

    dataGridView1.Columns.Add(new DataGridViewTextBoxColumn()
    {
        Name = "NameColumn",
        DataPropertyName = "Name",
        HeaderText = "Name"
    });
    dataGridView1.Columns.Add(new DataGridViewComboBoxColumn()
    {
        Name = "CategoryIdColumn",
        DataPropertyName = "CategoryId",
        HeaderText = "Category",
        DataSource = categories,
        ValueMember = "Id",
        DisplayMember = "Name",
        DisplayStyle= DataGridViewComboBoxDisplayStyle.Nothing
    });
    dataGridView1.DataSource = products;
    dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;
    dataGridView1.CellPainting += DataGridView1_CellPainting;
}

处理编辑控件显示

private void DataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    if (dataGridView1?.CurrentCell?.OwningColumn?.Name != "CategoryIdColumn")
        return;
    var combo = e.Control as DataGridViewComboBoxEditingControl;
    if (combo == null)
        return;

    combo.DrawMode = DrawMode.OwnerDrawFixed;
    combo.DrawItem += (obj, args) =>
    {
        var txt = args.Index >= 0 ? combo.GetItemText(combo.Items[args.Index]) : "";
        var textColor = args.Index == 0 ? SystemColors.GrayText : SystemColors.ControlText;
        var font = args.Index == 0 ? new Font(combo.Font, FontStyle.Italic) : combo.Font;
        if ((args.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
            textColor = SystemColors.HighlightText;
        }
        args.DrawBackground();
        TextRenderer.DrawText(args.Graphics, txt, font,
            args.Bounds, textColor,
            TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
    };
}

处理单元格绘画

private void DataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0 ||
            dataGridView1.Columns[e.ColumnIndex].Name != "CategoryIdColumn")
        return;
    if (dataGridView1[e.ColumnIndex, e.RowIndex].Value == DBNull.Value)
    {
        e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Italic);
        e.CellStyle.ForeColor = SystemColors.GrayText;
    }
    else
    {
        e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Regular);
        e.CellStyle.ForeColor = SystemColors.ControlText;
    }
}