A while ago i wrote about Exploring DataGridViewComboBoxColumn databinding using Business Objects. Some people asked me to give an example using DataSets…
I’ll start with creating a DataSet, add two DataTables, and create a relation on PersonType.Id (int32). In the designer this looks like:

Next i create a DataSetDac that will return an instance of a Filled PersonDataSet (In real life you would probably use a TableAdapter and get the data from a database) The code is as simple as:
public static PersonsDataSet Find()
{
PersonsDataSet personsDataSet = new PersonsDataSet();
personsDataSet.PersonType.Rows.Add(new object[] { 0, "A geeky person" });
personsDataSet.PersonType.Rows.Add(new object[] { 1, "A coward" });
personsDataSet.PersonType.Rows.Add(new object[] { 2, "Feeling hot hot hot" });
personsDataSet.PersonType.Rows.Add(new object[] { -1, "(None)" });
personsDataSet.Person.Rows.Add(new object[] { "Timvw", 0 });
personsDataSet.Person.Rows.Add(new object[] { "John Doe", 1 });
personsDataSet.Person.Rows.Add(new object[] { "An Onymous", 1 });
personsDataSet.Person.Rows.Add(new object[] { "Jenna Jameson", 2 });
personsDataSet.Person.Rows.Add(new object[] { "Null Able", -1 });
return personsDataSet;
}
And now comes the important stuff: Bind the data to the DataGridView and DataGridViewComboBoxColumn:
public Form1()
{
InitializeComponent();
PersonsDataSet personsDataSet = DataSetDac.Find();
this.dataGridView1.AutoGenerateColumns = false;
this.ColumnName.DataPropertyName = "Name";
this.ColumnPersonTypeCode.DataPropertyName = "PersonTypeId";
this.ColumnPersonTypeCode.DisplayMember = "Label";
this.ColumnPersonTypeCode.ValueMember = "Id";
this.ColumnPersonTypeCode.DataSource = personsDataSet.PersonType;
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = personsDataSet.Person;
this.dataGridView1.DataSource = bindingSource;
}
Geeks are doomed to stay Geeks forever. When you try change a Person that is a Geek, the values in ComboBox should be limited to Geek and (None). The following code takes care of that:
void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (this.dataGridView1.CurrentCell.ColumnIndex == this.ColumnPersonTypeCode.Index)
{
BindingSource bindingSource = this.dataGridView1.DataSource as BindingSource;
PersonsDataSet.PersonRow person = (bindingSource.Current as DataRowView).Row as PersonsDataSet.PersonRow;
// this method returns the allowed persontypes for the given person
PersonsDataSet.PersonTypeDataTable personTypeDataTable = DataSetDac.FindPersonTypes(person);
DataGridViewComboBoxEditingControl comboBox = e.Control as DataGridViewComboBoxEditingControl;
comboBox.DataSource = personTypeDataTable;
comboBox.SelectionChangeCommitted -= this.comboBox_SelectionChangeCommitted;
comboBox.SelectionChangeCommitted += this.comboBox_SelectionChangeCommitted;
}
}
public static PersonsDataSet.PersonTypeDataTable FindPersonTypes(PersonsDataSet.PersonRow person)
{
// by default, all persons simply have one of the available persontypecodes
PersonsDataSet personsDataSet = Find();
if (person.PersonTypeId.Equals(0))
{
// geeks are doomed to stay geeks
personsDataSet.PersonType.Rows.RemoveAt(2);
personsDataSet.PersonType.Rows.RemoveAt(1);
}
return personsDataSet.PersonType;
}
void comboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
this.dataGridView1.EndEdit();
}
As always, feel free to download DataGridViewComboBoxBinding2.zip.
bug?
thanks for this, but I found it doens’t work correctly. here is what I did.
1. click on first “persontypecode” dropdown, it is correct.
2. click on second one, and it shows corrrect.
3. click on the first dropdown again, it is good.
4. slick on second one again. the list is wrong, it shows as the first one.
and so on. to 3rd and 4th..etc
PS. don’t change the value for each drop down.
thanks!
The problem is that when the dropdownlist is shown, it selects the first value (a geeky person). As soon as you click on a different dropdown, that ‘new’ selection is committed (thus, the person becomes a geek), which explains why the next time the dropdown list is different.
Here is an implementation that does not have that unwanted behaviour:
void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { if (this.dataGridView1.CurrentCell.ColumnIndex == this.ColumnPersonTypeCode.Index) { BindingSource bindingSource = (BindingSource)this.dataGridView1.DataSource; PersonsDataSet.PersonRow person = (PersonsDataSet.PersonRow)((DataRowView)bindingSource.Current).Row; PersonsDataSet.PersonTypeDataTable personTypeDataTable = DataSetDac.FindPersonTypes(person); DataGridViewComboBoxEditingControl comboBox = (DataGridViewComboBoxEditingControl)e.Control; comboBox.DataSource = personTypeDataTable; // force the combobox to pick up the correct value. comboBox.SelectedValue = person.PersonTypeId; comboBox.SelectionChangeCommitted -= this.comboBox_SelectionChangeCommitted; comboBox.SelectionChangeCommitted += this.comboBox_SelectionChangeCommitted; } }I’ll post an updated zip package as soon as i’m able to setup an ftp connection.
EDIT 28/06/2008: I’ve uploaded (and overwritten) the zip file with the modification.