28

I have DataGridView with two columns. The first column is TextBoxCol(DataGridViewTextBoxColumn) and the Second one is ComboBoxCol(DataGridViewComboBoxColumn).

How can I change the value of TextBoxCol when ComboBoxCol changes its selected index value? (This should happen when selected index changed in ComboBoxCol. Not after leaving the column, like dataGridView_CellValueChanged)

I have read one topic with almost the same problem that I am having but I dont understand the answer(which should be correct base on the check mark). Here's the link. -Almost same topic

Community
  • 1
  • 1
Kalix Diona
  • 469
  • 1
  • 5
  • 10
  • Glad I could help, I'll keep an eye out for any more of your questions as I already have the project open :). – KreepN Jun 21 '12 at 18:25
  • 2
    Possible duplicate of [What event catches a change of value in a combobox in a DataGridViewCell?](http://stackoverflow.com/questions/5652957/what-event-catches-a-change-of-value-in-a-combobox-in-a-datagridviewcell) – Jim Fell Jun 15 '16 at 21:18

3 Answers3

51

This answer is floating around in a couple of places.

Using the DataGridViewEditingControlShowingEventHandler will fire more events than you intend. In my testing it fired the event multiple times.

Also using the combo.SelectedIndexChanged -= event will not really remove the event, they just keep stacking.

Anyway, I found a solution that seems to work. I'm including a code sample below:

// Add the events to listen for
dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
dataGridView1.CurrentCellDirtyStateChanged += new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);



// This event handler manually raises the CellValueChanged event 
// by calling the CommitEdit method. 
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        // This fires the cell value changed handler below
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
}

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    // My combobox column is the second one so I hard coded a 1, flavor to taste
    DataGridViewComboBoxCell cb = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[1];
    if (cb.Value != null)
    {
         // do stuff
         dataGridView1.Invalidate();
    }
}
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Severun
  • 2,893
  • 1
  • 16
  • 22
  • 1
    This really is better than the accepted solution. Only thing I had to change was adding if (e.RowIndex == -1) return; to the beginning of the dataGridView1_CellValueChanged function – Kevin Dec 01 '14 at 17:56
  • 2
    Yep, definitely a better solution, the selected one fires the event multiple times. – A B Apr 08 '15 at 09:21
  • 2
    Great answer, imho should be the accepted one!! Just one thing to add: Within the `CellValueChanged` handler you might wanna check which Column/Cell was changed instead of generally "doing stuff" ;-) E.g. `if (e.ColumnIndex == dataGridView1.Columns["Column2"].Index) ...` – Levite Nov 02 '15 at 09:41
  • 2
    You must call DataGridView.BeginEdit() after committing the change in the CurrentCellDirtyStateChanged event handler to put the "focus" back on the EditingControl (the ComboBox) and really make this behave like the ComboBox's SelectedIndexChanged event. – OfficeAddinDev Dec 23 '16 at 11:49
  • This is the best solution for me. With a little tweaking to limit the selected cell and you have a less hassle to solve – Mandz Feb 21 '17 at 03:42
  • 1
    That's the kind of voodoo .NET coders should include by default. It shouldn't be expected for a user to figure it out. – j riv Jun 14 '18 at 09:43
35

Give these two simple methods a go (the '1' in the top method is the index of the combobox column)

The line that you would make you modifications to would be the setter line cel.Value =, as you may change it to whatever you like.


    private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        if (dataGridView1.CurrentCell.ColumnIndex == 1 && e.Control is ComboBox)
        {
            ComboBox comboBox = e.Control as ComboBox;
            comboBox.SelectedIndexChanged -= LastColumnComboSelectionChanged;
            comboBox.SelectedIndexChanged += LastColumnComboSelectionChanged;
        }
    }

    private void LastColumnComboSelectionChanged(object sender, EventArgs e)
    {
        var currentcell = dataGridView1.CurrentCellAddress;
        var sendingCB = sender as DataGridViewComboBoxEditingControl;
        DataGridViewTextBoxCell cel = (DataGridViewTextBoxCell)dataGridView1.Rows[currentcell.Y].Cells[0];
        cel.Value = sendingCB.EditingControlFormattedValue.ToString();
    }

enter image description here

Community
  • 1
  • 1
KreepN
  • 8,528
  • 1
  • 40
  • 58
  • 8
    Make sure you also remove any existing event handlers with `comboBox.SelectedIndexChanged -= LastColumnComboSelectionChanged;` – Smashery Dec 13 '12 at 06:13
3

That link is correct. Handle the EditingControlShowing event of DataGridView. In this event handler, check if the current column is of your interest. And, then create a temporary combobox object :-

ComboBox comboBox = e.Control as ComboBox;

MSDN has a sample: See in the example section here. Note the Inheritance Hierarchy & Class Syntax in the msdn link : -

public class DataGridViewComboBoxEditingControl : ComboBox, IDataGridViewEditingControl

private DataGridView dataGridView1 = new DataGridView();

private void AddColorColumn()
{
    DataGridViewComboBoxColumn comboBoxColumn =
        new DataGridViewComboBoxColumn();
    comboBoxColumn.Items.AddRange(
        Color.Red, Color.Yellow, Color.Green, Color.Blue);
    comboBoxColumn.ValueType = typeof(Color);
    dataGridView1.Columns.Add(comboBoxColumn);
    dataGridView1.EditingControlShowing +=
        new DataGridViewEditingControlShowingEventHandler(
        dataGridView1_EditingControlShowing);
}

private void dataGridView1_EditingControlShowing(object sender,
    DataGridViewEditingControlShowingEventArgs e)
{
    ComboBox combo = e.Control as ComboBox;
    if (combo != null)
    {
        // Remove an existing event-handler, if present, to avoid 
        // adding multiple handlers when the editing control is reused.
        combo.SelectedIndexChanged -=
            new EventHandler(ComboBox_SelectedIndexChanged);

        // Add the event handler. 
        combo.SelectedIndexChanged +=
            new EventHandler(ComboBox_SelectedIndexChanged);
    }
}

private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
    ((ComboBox)sender).BackColor = (Color)((ComboBox)sender).SelectedItem;
}
Angshuman Agarwal
  • 4,796
  • 7
  • 41
  • 89