As explained in the comments above, DataGridViewComboBox
related issues might become tricky (you are basically adding a different control inside an-already-pretty-complex one); and what you aim does bring this configuration to its limits. DataGridView
is a control expected to ease the management of medium-complexity, data-related issues; you can get the best performance with its most defining features (e.g., textbox-based cells, events triggered after the cell has been validated, etc.). Thus, including comboboxes (or checkboxes or equivalent) cells is OK as far as you don't bring its performance to the limits. To get the best result possible for what you want (coordinating different comboboxes), I suggest you to not rely on a DataGridView
control (or, at least, not for the combobox coordination part) as far as the implemention is problematic, the final result not as reliable as it can get and, in any case, the overall structure much more rigid than the one resulting from a DGV-independent approach (i.e., individual ComboBox
controls).
In any case, I have felt curious about this implementation (mainly after seeing quite a few problems in my preliminary tests) and decided to write this code to answer your concern.
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.EditingControlShowing +=new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
DataGridViewComboBoxColumn curCol1 = new DataGridViewComboBoxColumn();
List<string> source1 = new List<string>() { "val1", "val2", "val3" };
curCol1.DataSource = source1;
DataGridViewComboBoxColumn curCol2 = new DataGridViewComboBoxColumn();
dataGridView1.Columns.Add(curCol1);
dataGridView1.Columns.Add(curCol2);
for (int i = 0; i <= 5; i++)
{
dataGridView1.Rows.Add();
dataGridView1[0, i].Value = source1[0];
changeSourceCol2((string)dataGridView1[0, i].Value, (DataGridViewComboBoxCell)dataGridView1[1, i]);
}
}
private void changeSourceCol2(string col1Val, DataGridViewComboBoxCell cellToChange)
{
if (col1Val != null)
{
List<string> source2 = new List<string>() { col1Val + "1", col1Val + "2", col1Val + "3" };
cellToChange.DataSource = source2;
cellToChange.Value = source2[0];
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.CurrentRow != null)
{
ComboBox col1Combo = e.Control as ComboBox;
if (col1Combo != null)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
col1Combo.SelectedIndexChanged += col1Combo_SelectedIndexChanged;
}
}
}
}
private void col1Combo_SelectedIndexChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
changeSourceCol2(dataGridView1.CurrentCell.Value.ToString(), (DataGridViewComboBoxCell)dataGridView1[1, dataGridView1.CurrentCell.RowIndex]);
}
}
This code works fine with one limitation: when you change the index of the first combobox, the value is not immediately committed (and thus the second combobox cannot be updated). After doing some tests, I have confirmed that the proposed configuration (i.e., just writing dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
before populating the second-combobox source delivers the best performance). Despite that, note that this code does not work perfectly on this front: it starts working (updating automatically the second combobox every time a new item is selected in the first one) from the second selection onwards; not sure about the exact reason of this but, as said, any other alternative I tried delivers a still worse performance. I haven't worked too much on this front because of my aforementioned comments (actually, doing this is not even recommendable) and because of feeling that you have to do part of the work.....