mega5800
mega5800

Reputation: 87

Winforms - applying MeasureItem & DrawItem events for only one combo box column

I am working on a winforms project that contains a data grid view which has two combo box columns. My goal is to make the first combo box column show specific items that match with certain condition.

I researched the topic and found that I need to listen to DataGridView's EditingControlShowing event to detect when the user opens a combo box for display. Then I need to cast the sender object to ComboBox object and listen to MeasureItem & DrawItem events. Now, I'll be able to draw the items that meet the condition and hide the rest.

Here are my source links: 1, 2, 3, 4

First, here's my code:

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 && dataGridView1.CurrentCell.ColumnIndex == 0)
            {
                comboBox.DrawItem -= ComboBox_DrawItem;
                comboBox.DrawItem += ComboBox_DrawItem;

                comboBox.MeasureItem -= ComboBox_MeasureItem;
                comboBox.MeasureItem += ComboBox_MeasureItem;

                comboBox.DrawMode = DrawMode.OwnerDrawVariable;
            }
        }

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

        private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (sender is DataGridViewComboBoxEditingControl comboBox && dataGridView1.CurrentCell.ColumnIndex == 0)
            {
                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;
        }
    }

Second, I can see the wanted result when I interact with the first column. For example: enter image description here

But the problem starts when I'm interacting with the second column which should display all the items:

enter image description here

I believe that reason for this problem is having the MeasureItem & DrawItem callback methods being invoked when the user is using the second combo box column.

My question is: How can I apply the logic above only for the first combo box column while keeping the original implementation for the second combo box column intact?

Thank you.

Upvotes: 0

Views: 163

Answers (0)

Related Questions