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

WinForms:仅为DataGridView首个ComboBox列应用MeasureItem与DrawItem事件

解决WinForms DataGridView多ComboBox列自定义绘制冲突问题

问题场景

开发WinForms项目时,DataGridView包含两个ComboBox列,要求第一列仅显示符合特定条件的项。通过监听EditingControlShowing事件给第一列ComboBox绑定MeasureItem和DrawItem事件实现了自定义绘制,但操作第二列时,本该显示全部项的ComboBox出现异常。

原因分析

DataGridView的编辑控件是复用的,切换到第二列时,之前给第一列ComboBox绑定的自定义绘制事件未被移除,导致第二列的ComboBox也执行了自定义逻辑,从而显示异常。

解决方案

核心思路:在EditingControlShowing事件中,先无条件移除之前绑定的自定义事件,再根据当前列判断是否需要重新绑定并开启自定义绘制,非目标列则恢复默认绘制模式。

修改后的完整代码

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        DataGridViewComboBoxColumn first_column = new DataGridViewComboBoxColumn();
        first_column.Name = "First";
        first_column.Items.Add("A");
        first_column.Items.Add("B");
        first_column.Items.Add("C");
        first_column.Items.Add("D");
        dataGridView1.Columns.Add(first_column);

        DataGridViewComboBoxColumn second_column = new DataGridViewComboBoxColumn();
        second_column.Name = "Second";
        second_column.Items.Add("1");
        second_column.Items.Add("2");
        second_column.Items.Add("3");
        second_column.Items.Add("4");
        dataGridView1.Columns.Add(second_column);

        dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;
    }

    private void DataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        ComboBox comboBox = e.Control as ComboBox;
        if (comboBox != null)
        {
            // 先移除所有自定义事件绑定,避免控件复用残留事件
            comboBox.DrawItem -= ComboBox_DrawItem;
            comboBox.MeasureItem -= ComboBox_MeasureItem;
            
            // 仅对第一列应用自定义绘制逻辑
            if (dataGridView1.CurrentCell.ColumnIndex == 0)
            {
                comboBox.DrawItem += ComboBox_DrawItem;
                comboBox.MeasureItem += ComboBox_MeasureItem;
                comboBox.DrawMode = DrawMode.OwnerDrawVariable;
            }
            else
            {
                // 恢复第二列的默认绘制模式
                comboBox.DrawMode = DrawMode.Normal;
            }
        }
    }

    private void ComboBox_MeasureItem(object sender, MeasureItemEventArgs e)
    {
        if (sender is DataGridViewComboBoxEditingControl comboBox)
        {
            if (!canDraw(e.Index))
            {
                e.ItemHeight = 0;
            }
        }
    }

    private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
    {
        if (sender is DataGridViewComboBoxEditingControl comboBox)
        {
            if (canDraw(e.Index))
            {
                Brush foregroundBrush = Brushes.Black;
                e.DrawBackground();
                e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), e.Font, foregroundBrush, e.Bounds, StringFormat.GenericDefault);
                e.DrawFocusRectangle();
            }
        }
    }

    private bool canDraw(int index)
    {
        return index > -1 && index % 2 == 0;
    }
}

关键修改点

  1. 事件清理优先:每次进入编辑状态时,先移除自定义事件绑定,彻底避免控件复用导致的事件残留
  2. 区分列逻辑:仅对第一列绑定自定义绘制事件,第二列强制恢复Normal绘制模式,使用默认逻辑
  3. 简化判断逻辑:移除MeasureItem和DrawItem方法中多余的列索引判断,因为只有第一列会触发这些事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:07:11