Please see picture. The DataGridView is in mixed mode. The Animal column is bound but the Class column is not. The Animal column will contain items like Dog, Chicken, Turtle, Bear, etc. The idea is for the user to select the Class each animal belongs to, such as Mammal, Reptile, Bird, Amphibian, etc.
The combobox will be different in each row, so I can't set it at the column level. According to the documentation, you should handle the CellValueNeeded event, which is called for each unbound cell. And that's where the fun begins.
The un-commented code in the CellValueNeeded event somehow creates a situation where the CellValueNeeded event is called repeatedly, resulting in a StackOverflowException within seconds. You'll notice a couple of commented lines in this event referring to a text box. As an experiment, I changed the combo box to a text box, and it worked fine, without problems. But nothing I do with the cell as a combo box seems to work. It always blows the stack.
Now, outside of that event, in the form constructor, that same code works just fine, but I was hoping not to have to do that. In theory, catching the unbound cells as the DataGridView is filled seems pretty elegant.
I read that the problem may have something to do with the value supplied to the comb box, and that I should handle the DataError event. However, the DataError event never fires. Breakpoints there never hit.
Any ideas how to do this are welcome!
using System.Windows.Forms; using System.Collections.Generic; using System.ComponentModel; namespace Requester { public partial class Form1 : Form { struct DGVRows { public string Animal { get; set; } } struct DGVCombo { public int Value { get; set; } public string Display { get; set; } } BindingList<DGVRows> RowList = new BindingList<DGVRows>(); public Form1() { InitializeComponent(); dataGridView1.AutoGenerateColumns = false; var NewRow = new DGVRows(); NewRow.Animal = "Dog"; RowList.Add(NewRow); NewRow.Animal = "Trout"; RowList.Add(NewRow); NewRow.Animal = "Lizard"; RowList.Add(NewRow); NewRow.Animal = "Chicken"; RowList.Add(NewRow); dataGridView1.DataSource = RowList; Animal.DataPropertyName = "Animal"; //foreach (DataGridViewRow dgvrow in dataGridView1.Rows) //{ // var Combo = new List<DGVCombo>(); // var x = new DGVCombo(); // x.Value = 1; // x.Display = "Mammal"; // Combo.Add(x); // x.Value = 2; // x.Display = "Reptile"; // Combo.Add(x); // x.Value = 3; // x.Display = "Amphibian"; // Combo.Add(x); // var cmb = (dgvrow.Cells[1] as DataGridViewComboBoxCell); // cmb.ValueMember = "Value"; // cmb.DisplayMember = "Display"; // cmb.DataSource = Combo; //} } private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { if (e.ColumnIndex == 1) { //var dgvtxt = (dgv.Rows[e.RowIndex].Cells[1] as DataGridViewTextBoxCell); //e.Value = "sf"; //var dgv = sender as DataGridView; //var dgvcmb = (dgv.Rows[e.RowIndex].Cells[1] as DataGridViewComboBoxCell); //dgvcmb.Items.AddRange(new string[] { "A", "B", "C" }); //dgvcmb.Value = dgvcmb.Items[1]; //e.Value = dgvcmb.Value; var Combo = new List<DGVCombo>(); var x = new DGVCombo(); x.Value = 1; x.Display = "Mammal"; Combo.Add(x); x.Value = 2; x.Display = "Reptile"; Combo.Add(x); x.Value = 3; x.Display = "Amphibian"; Combo.Add(x); var dgv = sender as DataGridView; var cmb = (dgv.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewComboBoxCell); cmb.ValueMember = "Value"; cmb.DisplayMember = "Display"; cmb.DataSource = Combo; cmb.Value = "Mammal"; e.Value = cmb.Value; } } private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) { e.Cancel = true; } } }