Hello,
I am trying to bind a BindingList to a DataGridView, the type inside biding list has a refrence type to a foreign key object, and my goal is to display this foreign key object in a DropDownList in the DataGridView. In order to explain the problem, first allow me to introduce couple of simplified domain classes:
class State{
Guid id;
string name;
public State() {
id = Guid.NewGuid();
}
public State(Guid id, string name) {
this.id = id;
this.name = name;
}
public Guid Id {
get { return id; }
}
public string Name {
get { return name; }
set { name = value;}
}
}
And also:
class City{
Guid id;
string name;
State state; public City() {
id = Guid.NewGuid();
} public City(Guid id, string name, State state) {
this.id = id;
this.name = name;
this.state = state;
} public Guid Id {
get { return id; }
}
public string Name {
get { return name; }
set { name = value; }
}
get { return state; }
set { state = value; }
}
}
This classes are filled with DataMappers on the server side but for the sake of simplicity I am providing a dummy class here which provide a list for the DataGridView,
static class DataBuilder{
static State AB;
static State BC; static BindingList<State> stateList = null;
public static BindingList<State> StateList {
get {
if (stateList == null) {
stateList = new BindingList<State>();
AB = AB new State(Guid.NewGuid(), "Albeta");
BC = BC new State(Guid.NewGuid(), "British Columbia"); stateList.Add(AB);
stateList.Add(BC);
}
return stateList;
}
} static BindingList<City> cityList = null;
public static BindingList<City> CityList
{
get {
if (cityList == null) {
AB = AB new State(Guid.NewGuid(), "Albeta");
BC = BC new State(Guid.NewGuid(), "British Columbia"); cityList = new BindingList<City>();
cityList.Add(new City(Guid.NewGuid(), "Vancouver", BC));
cityList.Add(new City(Guid.NewGuid(), "Burnaby", BC));
cityList.Add(new City(Guid.NewGuid(), "Richmond", BC));
cityList.Add(new City(Guid.NewGuid(), "Edmonton", AB));
cityList.Add(new City(Guid.NewGuid(), "Calgary", AB));
}
return cityList;
}
}
}
Now the question is how can I bind DataBuilder.CityList to a DataGridView that I can see the list of the Cities with the approriate province selected in the DataGridViewComboBoxButton, and also take advatage of the power of binding and particularly BindingList
The problem is I am not quite sure what should put in the DataPropertyName propert of the ComboBoxButton, I have tried to override the ToString method of the State class to return a name but I am getting "DataGridViewComboBoxCell value is not valid" error, I have changed the ValueType of the DataGridViewComboBoxCell to typeof(State) but for some reason on the runtime it is a Guid.
Many thanks.

DataGridViewComboBoxColumn and binding to a Custom Collection (BindingList<T>)
Ramirez3964
thanks
aRman
Simsabim
{
if (e.RowIndex == grid.RowCount - 1) return;
if (e.ColumnIndex == MunicipalityList.Index)
{
City city = grid.Rows[e.RowIndex].DataBoundItem as City;
if (city == null || city.Municipality == null) return;
e.Value = city.Municipality.Id;
private void OnCellValuePushed(object sender, DataGridViewCellValueEventArgs e)}
}
{
if (e.ColumnIndex == MunicipalityList.Index)
{
City city = grid.Rows[e.RowIndex].DataBoundItem as City; if (city == null) return; int id = (int)e.Value; Municipality municipal = MuncipalitiesCached[id]; // I have cached all the municipality in a Dictionary<id, Municipality> ***
city.Municipality =
municipal;}
}
On other way is to use populate the list with the municipality object like this:
foreach(Municipality municipal in Municipalities) lstMunicipality.Items.Add( municipal);
Ofcourse you have to override the ToString method of municipality to return the name, then in the CellValuePushed what is come back is e.Value is the municipality itself not its ID then you don't have to cache them in memory.
CTRon
Ok I solve the problem in a lousy way!
First on the Form Load I bind the Grid and the ComboBox Like this:
dataGridView1.AutoGenerateColumns =
false;StateName.DisplayMember = "Name";
StateName.ValueMember = "Id";
StateName.DataPropertyName = string.Empty;
StateName.DataSource = DataBuilder.StateList;
dataGridView1.DataSource =
DataBuilder.CityList;then on CellFormatting event of the grid i did:
if (dataGridView1.Rows[e.RowIndex].IsNewRow) return;if (StateName.Index != e.ColumnIndex) return;
DataGridViewComboBoxCell stateCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[StateName.Index];
City city = (City)dataGridView1.Rows[e.RowIndex].DataBoundItem;
if (city.State == null || String.IsNullOrEmpty(city.State.Name)) return;
stateCell.Value = city.State.Id;
I had to also capture the CellValueChanged event of the Grid, like this:
if (e.RowIndex < 0) return; if (e.ColumnIndex == StateName.Index) {City city = (City)dataGridView1.Rows[e.RowIndex].DataBoundItem;
if (city == null) return; DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)dataGridView1.Rows [e.RowIndex].Cells[StateName.Index]; if (cell.Value == null) return; Guid stateId = (Guid)cell.Value; string stateName = cell.FormattedValue.ToString();
city.State =
new State(stateId, stateName);This apparently solves the problem, however I haven't unit test it throughly and i will post it here if I face any other problem.
But is there any better way to approach this
Thanks,
Jandler2
I put this comment for those who might have the same problem. The above solution that I wrote while ago, is inadequate. It is better to set the virtual mode of the grid to true and use the CellValueNeeded and CellValuePushed method instead.