DataGridView with a ComboBox column error (listing objects)

G

gsa

Scenario:
Two classes (objA and objX), the class objX has a field of type objA.

class objA {
private double _a;
public double a {
get { return _a; }
set { _a = value; }
}
private int _b;
public int b {
get { return _b; }
set { _b = value; }
}
public override string ToString() {return _a.ToString();}
}

class objX {
private objA _objA;
public objA A {
get { return _objA; }
set { _objA = value; }
}
//...
}

Several instances of both objects.

objA a = new objA(); objA b = new objA(); objA c = new objA();
a.a = 1.1; a.b = 1;
b.a = 2.2; b.b = 2;
c.a = 3.3; c.b = 3;

objX x = new objX(); objX y = new objX(); objX z = new objX();
x.A = a;
y.A = b;
z.A = c;

A DataGridView with a ComboBox column showing the list of objX objects,
and the combobox(es) having the objAs in the list using
BindingSource(s) to populate everything. Like this:

comboBS.Add(a);
comboBS.Add(b);
comboBS.Add(c);
gridBS.Add(x);
gridBS.Add(y);
gridBS.Add(z);
DataGridViewComboBoxCell cell = new DataGridViewComboBoxCell();
cell.DataSource = this.comboBS;
cell.Value = typeof(objA);
cell.ValueType = typeof(objA);
dataGridView1.Columns[0].CellTemplate = cell;

where comboBS and gridBS are BindingSource(s) created within the Visual
Sudio IDE.

Now, everything works fine and the grid appears on the screen, showing
correct values in each cell.

Trying to change one of the combobox values, however, raises an
exception in the DataGridViiew of type System.FormatException (Invalid
cast from System.String to objA).

Note that no field in both object is of type String, so there must be
some internal representation wich the grid uses and then tries to cast.

I googoled for days but found only samples and articles showing
DataGridView using database tables as data, NOT objects.

Thank You for any help,
gsa
 
B

Bart Mermuys

Hi,

gsa said:
Scenario:
Two classes (objA and objX), the class objX has a field of type objA.

class objA {
private double _a;
public double a {
get { return _a; }
set { _a = value; }
}
private int _b;
public int b {
get { return _b; }
set { _b = value; }
}
public override string ToString() {return _a.ToString();}
}

class objX {
private objA _objA;
public objA A {
get { return _objA; }
set { _objA = value; }
}
//...
}

Several instances of both objects.

objA a = new objA(); objA b = new objA(); objA c = new objA();
a.a = 1.1; a.b = 1;
b.a = 2.2; b.b = 2;
c.a = 3.3; c.b = 3;

objX x = new objX(); objX y = new objX(); objX z = new objX();
x.A = a;
y.A = b;
z.A = c;

A DataGridView with a ComboBox column showing the list of objX objects,
and the combobox(es) having the objAs in the list using
BindingSource(s) to populate everything. Like this:

comboBS.Add(a);
comboBS.Add(b);
comboBS.Add(c);
gridBS.Add(x);
gridBS.Add(y);
gridBS.Add(z);
DataGridViewComboBoxCell cell = new DataGridViewComboBoxCell();
cell.DataSource = this.comboBS;
cell.Value = typeof(objA);
cell.ValueType = typeof(objA);
dataGridView1.Columns[0].CellTemplate = cell;

where comboBS and gridBS are BindingSource(s) created within the Visual
Sudio IDE.

Now, everything works fine and the grid appears on the screen, showing
correct values in each cell.

Trying to change one of the combobox values, however, raises an exception
in the DataGridViiew of type System.FormatException (Invalid cast from
System.String to objA).

Note that no field in both object is of type String, so there must be some
internal representation wich the grid uses and then tries to cast.

Yes, the DataGridView persists values in three steps:
- get DGVComboBoxEditingControl.EditingControlFormattedValue
- pass to DGVComboBoxCell.ParseFormattedValue (parse&lookup)
- store (parsed) value

DGVComboBoxEditingControl.EditingControlFormattedValue always returns a
string, it's the Text property value of the editing ComboBox.

Inside DGVComboBoxCell.ParseFormattedValue it goes wrong, it should lookup
the value inside the DataSource or Items but it doesn't because there is no
DisplayMember or ValueMember set. The problem in your case is not the
DisplayMember (which you could easily set), but the ValueMember.
ValueMember indicates a property on the row/object that is a primary key and
that will be matched against the foreign keys inside the master
rows/objects.

In your case ValueMember should point to your lookup object reference
instead of a property of it, unfortunetaly i couldn't find a way to do this,
but you can change your class a little to make it work:

class objA {
private double _a;
public double a {
get { return _a; }
set { _a = value; }
}

private int _b;
public int b {
get { return _b; }
set { _b = value; }
}

public objA This { get { return this; } }
}

class objX { .... }

comboBS.Add(a);
comboBS.Add(b);
comboBS.Add(c);

gridBS.Add(x);
gridBS.Add(y);
gridBS.Add(z);

DataGridViewComboBoxColumn comboBoxColumn =
new DataGridViewComboBoxColumn();

comboBoxColumn.DataPropertyName = "A";

comboBoxColumn.DataSource = this.comboBS;
comboBoxColumn.DisplayMember = "a";
comboBoxColumn.ValueMember = "This";

dataGridView1.Columns.Add(comboBoxColumn);


The following will happen now: when the ComboBox displays one of your
objects, it will use the "DisplayMember" property, which in your case is "a"
(propertytype=double), so it will format it to a string. And
EditingFormattedValue will be that string.

Then when DGVComboBox.ParseFormattedValue is called, it will first convert
the FormattedValue to a double (because of the DisplayMember), then it will
look it up and return the value of the ValueMember (which is This, the
object itself) property.

HTH,
Greetings
 
G

gsa

Bart, thank you SO much, it works great. And very very clear
explanation, also. Maybe the DataGridView, which indeed is very
beautiful, deserves some better documentation...?

Cheers,
gsa

BTW: are you from Microsoft or just a solitary genius ;) ?
 
B

Bart Mermuys

Hi,

gsa said:
Bart, thank you SO much, it works great. And very very clear explanation,
also.

Glad it helped.
Maybe the DataGridView, which indeed is very beautiful, deserves some
better documentation...?

There is an FAQ about the DataGridView here: (not sure if it deals with
this problem though)
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=152467&SiteID=1
Cheers,
gsa

BTW: are you from Microsoft or just a solitary genius ;) ?

I quess neither :), just a bit interested in DataBinding.

Thanks for the feedback,
Greetings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top