Click here to Skip to main content
15,891,864 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I have a very simple sample application below. This is for Windows Forms, and should have a matching for created in Designer with a DataGridView that has two columns: Name, and Department. Department is a DataGridViewComboBoxCell.

The grid lists data as expected, and the combo-box list its items as expected. However, I cannot get the data selected in the combo-box tied to the DataBoundItem of the grid. For example, when the app first starts, my only Person object has a DepartmentID = 2, which matches a value in the combo-box, but nothing is selected in the combo-box. When something is selected in the combo-box, it does not get reflected in the Person object.

There is a commented-out line of code for setting ValueMember, but this causes a "Field called DeptID does not exist" error.

It is important that both data sets are ArrayList and not DataTable.

How do I complete the binding between row data and combo-box selection?

--- Full project code is below ---

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestApp
{
	public partial class Form1 : Form
	{
		private ArrayList personList = new ArrayList();
		private ArrayList deptList = new ArrayList();
		BindingSource m_BindSource = new BindingSource();
		public Form1()
		{
			InitializeComponent();
		}
		private void Form1_Load(object sender, EventArgs e)
		{
			personList.Add(new Person("Tim", 2));
			deptList.Add(new Department("A", 1));
			deptList.Add(new Department("B", 2));
			deptList.Add(new Department("C", 3));
			DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)grid1.Columns[1].CellTemplate;
			cell.DataSource = deptList;
			cell.DisplayMember = "DeptName";
			//cell.ValueMember = "DeptID";	// "Field called DeptID does not exist"
			try
			{
				m_BindSource.DataSource = null;
				m_BindSource.DataSource = personList;
				grid1.DataSource = m_BindSource;
			}
			catch (Exception ex)
			{
				ex.GetType();
				MessageBox.Show(ex.Message);
			}
		}
	}
	public class Person
	{
		public Person(String name, int deptID)
		{
			PersonName = name;
			DepartmentID = deptID;
		}
		private String m_PersonName;
		public String PersonName
		{
			get { return m_PersonName; }
			set { m_PersonName = value; }
		}
		private int m_DepartmentID;
		public int DepartmentID
		{
			get { return m_DepartmentID; }
			set { m_DepartmentID = value; }
		}
	}
	public class Department
	{
		public Department(String name, int deptID)
		{
			DeptName = name;
			DepartmentID = deptID;
		}
		private String m_DeptName;
		public String DeptName
		{
			get { return m_DeptName; }
			set { m_DeptName = value; }
		}
		private int m_DepartmentID;
		public int DepartmentID
		{
			get { return m_DepartmentID; }
			set { m_DepartmentID = value; }
		}
	}
}
Posted
Updated 18-Jun-18 9:38am
Comments
Sergey Alexandrovich Kryukov 15-Apr-13 13:59pm    
Just a note: never use ArrayList in new development, always use System.Collections.Generic.List<>
—SA

1 solution

After much research and tinkering, I found the solution. Below is the body of Form1_Load() that works. There are two parts to the solution:

1) Instead of creating the cell/column on the fly, just build it into the design-time view and bind appropriately as shown below the catch() statement

2) The grid will not automatically match up row data with combobox data as I am used to. The for-loop at the end goes through and binds the existing row data selection to the corresponding entry in the combobox.

As an additional note, I found that this solution has additional problems if the DataGridView is located in a tab control. If the grid is on any tab other than the first one, the row/combobox binding will fail. Whether this is a MS bug or not I don't know, but the solution was to put the for-loop in the code below in the SelectedIndexChanged() event for the tab control and run it when changing to the tab in question.

C#
personList.Add(new Person("Tim", 2));   // Create one Person data object and add it to the list used by the DataGridView

// Create a list of Departments to be used by the combo box in the DataGridView
deptList.Add(new Department("A", 1));
deptList.Add(new Department("B", 2));
deptList.Add(new Department("C", 3));

grid1.AutoGenerateColumns = false;  // If we don't do this, the DepartmentID shows up as an additional column

try // Bind the Person list to the DataGridView
{
    m_BindSource.DataSource = null;
    m_BindSource.DataSource = personList;
    grid1.DataSource = m_BindSource;
}
catch (Exception ex)
{
    ex.GetType();
    MessageBox.Show(ex.Message);
}

// Bind the Department data to the appropriate column in the DataGridView
((DataGridViewComboBoxColumn)grid1.Columns["Department"]).DataSource = deptList;
((DataGridViewComboBoxColumn)grid1.Columns["Department"]).DisplayMember = "DeptName";
((DataGridViewComboBoxColumn)grid1.Columns["Department"]).ValueMember = "DeptID";

// Since the DataGridView won't automatically sync the Department list with each Person's DepartmentID, we have to manually link the two. This is what
// causes the combo box to show the proper selection for each Person's Department in the grid of existing data.
foreach (DataGridViewRow row in grid1.Rows)
{
    if (row.DataBoundItem != null)
    {
        row.Cells["Department"].Value = ((Person)row.DataBoundItem).DepartmentID;
    }
}
 
Share this answer
 
Comments
Member 13847218 20-Jun-18 5:09am    
how do insert windows application c# text box values same value no save sql

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900