I have a DataGridView
that has a ComboBox
column and I must update each ComboBox's possible values when its drop down shows. I also must make the ComboBox
es capable of having custom typed values. When a new value is typed, it should be added to the list of possible values. The problem is that I get infinitely many DataError
event triggers (error message boxes), I know how to handle it by just changing a field in the DataGridViewDataErrorEventArgs
object, but I know it is not the correct way to handle it:
private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = false;
}
If I do it in the incorrect way, after selecting a value from the drop down or typing a new value, the CellValueChanged
is triggered but the closed ComboBox
does not display the current value but an already existing value (the first in the list).
In the following code the Form subclass is Form2
, the initial values are stored in the str
field and the UpdatePossibleValues
method is called to update the possible values in all the ComboBox
es inside the only column in the data grid view, a DataGridViewComboBoxColumn
:
public Form2()
{
InitializeComponent();
dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;
UpdatePossibleValues();
}
internal List<string> str = new List<string>()
{
"val1",
"val2"
};
private void DataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.CurrentCell == null ||
dataGridView1.CurrentCell.OwningColumn == null ||
dataGridView1.CurrentCell.OwningColumn.Name != "column1")
{
return;
}
var combo = e.Control as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
var cb = combo as ComboBox;
UpdatePossibleValues(cb);
cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
cb.Validating += Cb_Validating;
}
private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
var cbo = sender as ComboBox;
string t = cbo.Text;
var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;
// add the value to the list if it is not there
if (!string.IsNullOrEmpty(t) &&
!cbo.Items.Contains(t))
{
str.Add(t);
UpdatePossibleValues(cbo);
cell.Value = t;
e.Cancel = false;
}
}
private void UpdatePossibleValues(ComboBox cb = null)
{
if (cb == null)
{
var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;
col.Items.Clear();
foreach (string s in str)
{
col.Items.Add(s);
}
}
else
{
cb.Items.Clear();
foreach (string s in str)
{
cb.Items.Add(s);
}
}
}
Screenshots:
To dynamically add item to
DataGridViewComboBoxColumn
:EditingControlShowing
and get theDataGridViewComboBoxEditingControl
DropDownStyle
toDropDown
Validating
event of editing control and make sure you attach the event handler just once.Text
of the editing control doesn't exists in the items:Notes:
If you have multiple combo box, make sure you use different data sources for combo boxes and update corresponding data source in validating event.
If you handle the events using anonymous method, make sure you have a correct assumption about captured variables. To make it simple, you can handle the event using a normal method.
Example
The following example shows a
DataGridView
having twoDataGridViewComboBoxColumn
which for the second one, you can add new values by typing in the combo box at run-time.To run the example, create a
Form
and drop aDataGridView
on a new Form and just copy and paste the following code in the form: