DataGridView and ComboBoxColumn

B

Brian Pelton

This is on .Net 2.0 in a WinForms application.

I have a DataGridView that is bound to a BindingSource. The
DataGridView has 3 columns. The first two are "normal" text columns and
the last is a combo box column.

Data binding is working fine for the first two columns. I am able to
edit values and persist them back to the bound object and ultimately
back to the database.

Data binding for the combo box column only shows the current value. I
cannot change it.


Here is the code for creating the combo box column:

DataGridViewComboBoxColumn dgvcQuantityUom =
new DataGridViewComboBoxColumn();
dgvcQuantityUom.Name = "QuantityUom";
dgvcQuantityUom.DataPropertyName = "QuantityUom";
dgvcQuantityUom.HeaderText = "Uom";
dgvcQuantityUom.DataSource = _uomList;
dgvcQuantityUom.DisplayMember = "UomName";

So, this column is bound to the property "QuantityUom". That property
is of the type "Uom" (Unit of Measure).

_uomList is an IList<Uom> of Uom objects. This is the drop down list
for the combo box.


---

When I do databinding for "normal" comob box controls outside of a
datagrid, I have a line that sets up the databinding:

myComboBox.DataBindings.Add("SelectedItem", myDataBindingSource,
"NameOfProperty");

But I don't see how I can get to the databindings for the DataGridView's
combo box.



Any ideas??

Brian
 
O

Otis Mukinfus

This is on .Net 2.0 in a WinForms application.

I have a DataGridView that is bound to a BindingSource. The
DataGridView has 3 columns. The first two are "normal" text columns and
the last is a combo box column.

Data binding is working fine for the first two columns. I am able to
edit values and persist them back to the bound object and ultimately
back to the database.

Data binding for the combo box column only shows the current value. I
cannot change it.


Here is the code for creating the combo box column:

DataGridViewComboBoxColumn dgvcQuantityUom =
new DataGridViewComboBoxColumn();
dgvcQuantityUom.Name = "QuantityUom";
dgvcQuantityUom.DataPropertyName = "QuantityUom";
dgvcQuantityUom.HeaderText = "Uom";
dgvcQuantityUom.DataSource = _uomList;
dgvcQuantityUom.DisplayMember = "UomName";

So, this column is bound to the property "QuantityUom". That property
is of the type "Uom" (Unit of Measure).

_uomList is an IList<Uom> of Uom objects. This is the drop down list
for the combo box.


---

When I do databinding for "normal" comob box controls outside of a
datagrid, I have a line that sets up the databinding:

myComboBox.DataBindings.Add("SelectedItem", myDataBindingSource,
"NameOfProperty");

But I don't see how I can get to the databindings for the DataGridView's
combo box.



Any ideas??

Brian
Hello Brian,

When you bind a DataGridView Combobox You will need to set the DisplayItem and
ValueItem property both. If you are not using a separate lookup table to supply
the Display value, then set the display value and the value item both to the
data that is shown in the dropdown.

If you are saving the row id from a table that contains the list into the table
that the other columns are in, you will need to supply a list that contains both
the display text and the Row ID from the lookup table. Set the display item of
the combo box to the text value and the value item to the row id of the lookup
table.

If you are using a datatable from a dataset you will be able to set this in the
column editor dialog.

Good luck with your project,

Otis Mukinfus
http://www.arltex.com
http://www.tomchilders.com
 
L

Linda Liu [MSFT]

Hi Brian,
So, this column is bound to the property "QuantityUom". That property is
of the type "Uom" (Unit of Measure).

Do you mean that the QuantityUom property which is bound to the
DataGridView combobox column is of a complex type 'Uom'? Generally
speaking, we bind a property of a simple type to a DataGridView combobox
column.

I noticed that you don't set the ValueMember property of the
DataGridViewComboBoxColumn. If you have set the DataPropertyName property
of the DataGridView combobox column, you should set the DataSource,
DisplayMember and ValueMember properties all.

If the problem is still not resolved, you may send me your sample project
that could just reproduce the problem. To get my actual email address,
remove 'online' from my displayed email address.


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Linda,
I did what you said and now when I click on the combobox I get a completely
diff error. to o long to show here (I wish I couls attaech it). But it is
somethign liek this:

"current thread must be set to single thread apartment (STA) mode before OLE
cals can be made. Ensure your main function has STAThreadAttributemarked on
it".

What?? ;o)
 
B

Brian Pelton

Linda said:
Do you mean that the QuantityUom property which is bound to the
DataGridView combobox column is of a complex type 'Uom'? Generally
speaking, we bind a property of a simple type to a DataGridView combobox
column.

Yes. It is bound to a complex type 'Uom'.

I'm realizing that DataGridView combobox doesn't handle complex types well.
I noticed that you don't set the ValueMember property of the
DataGridViewComboBoxColumn. If you have set the DataPropertyName property
of the DataGridView combobox column, you should set the DataSource,
DisplayMember and ValueMember properties all.

I didn't set ValueMember because I don't want to pass back a property of
my list back to my data source. I want to pass the actual Uom object.

Is there a way I can intercept the Parse & Formatting events for the
combo box? Perhaps the DataGridView.DataBindings[""].Parse event? I
can translate the ValueMember of "10" back to a Uom object?


Am I better off to try an write a new DataGridView column type that
handles complex types?

--Brian
 
B

Brian Pelton

Chris said:
"current thread must be set to single thread apartment (STA) mode before OLE
cals can be made. Ensure your main function has STAThreadAttributemarked on
it".

What?? ;o)

In your Main() method that starts your application, add [STAThred]


Code:
using System;

namespace YourProgramNamespace
{
static class Program
{
[STAThread]
static void Main()
{
}
}
}
 
L

Linda Liu [MSFT]

Hi Brian,

Thank you for your prompt response.

I have peformed a test on this, and when the program is run, I get an error
saying that 'DataGridViewComboBoxCell value is not valid'. So I don't think
it's a good practice to bind a property of a complex type to a
DataGridViewComboBoxColumn.

I suggest that you don't bind the QuantityUom property to the
DataGridViewComboBoxColumn. Instead, you could paint the value in the
corresponding cells by yourself, which would be more flexible and easy.

In detail, you may handle the CellPainting event of the DataGridView to set
the value of the cell (e.g. the value of 10). To save the updated value to
the data source, you should also handle the CellValidated event of the
DataGridView to set the new object to the data source.

The following is a sample, which assumes that you add a DataGridView on a
form and add two columns into the DataGridView. The first column is of type
DataGridViewTextBoxColumn and the second column is of type
DataGridViewComboBoxColumn.

public partial class Form2 : Form
{
MyList addresses = new MyList();
List<Person> persons = new List<Person>();
public Form1()
{
InitializeComponent();

this.dataGridView1.CellPainting += new
DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);
this.dataGridView1.CellValidated += new
DataGridViewCellEventHandler(dataGridView1_CellValidated);
}

void dataGridView1_CellValidated(object sender,
DataGridViewCellEventArgs e)
{
// the cells under the column of index 1 are going to display
the property of a complex type
if (e.ColumnIndex == 1 && e.RowIndex > -1)
{
if
(this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
{
string val =
this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
persons[e.RowIndex].Addr =
this.addresses.GetAddress(val);
}
}
}

void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 1 && e.RowIndex > -1)
{

this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value =
persons[e.RowIndex].Addr.ID;
}
}

private void Form1_Load(object sender, EventArgs e)
{
Address addr = new Address("1", "cityA");
addresses.Add(addr);

addr = new Address("2", "CityB");
addresses.Add(addr);

addr = new Address("3", "CityC");
addresses.Add(addr);

Person per = new Person("1", addresses[0]);
persons.Add(per);

per = new Person("2", addresses[1]);
persons.Add(per);

per = new Person("3", addresses[2]);
persons.Add(per);

this.dataGridView1.AutoGenerateColumns = false;
this.dataGridView1.DataSource = persons;
this.dataGridView1.Columns[0].DataPropertyName = "ID";

(this.dataGridView1.Columns[1] as
DataGridViewComboBoxColumn).DataSource = addresses;
(this.dataGridView1.Columns[1] as
DataGridViewComboBoxColumn).DisplayMember = "City";
(this.dataGridView1.Columns[1] as
DataGridViewComboBoxColumn).ValueMember = "ID";
}

public class Person
{
private string id;
public string ID
{
get { return id; }
set { id = value; }
}
private Address addr;
public Address Addr
{
get { return addr; }
set { addr = value; }
}
public Person(string id, Address addr)
{
this.id = id;
this.addr = addr;
}

}
public class Address
{
private string id;
public string ID
{
get { return id; }
set { id = value; }
}
private string city;
public string City
{
get { return city; }
set { city = value; }
}
public Address(string id, string city)
{
this.id = id;
this.city = city;
}
}
public class MyList:List<Address>
{
public Address GetAddress(string id)
{
Address addr = null;
for (int i = 0; i < this.Count; i++)
{
if (this.ID == id)
{
addr = this;
break;
}
}
return addr;
}
}
}

Hope this helps.
If you have any questions, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
L

Linda Liu [MSFT]

Hi Brian,

How about the problem now?

If the problem is still not solved, please feel free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!


Sincerely,
Linda Liu
Microsoft Online Community Support
 
B

Brian Pelton

Linda said:
How about the problem now?


Hi Linda,

Thanks for following up. I haven't tried your suggestion yet. I was
looking for a cleaner way to do it. I'm looking at purchasing a grid
component from a component vendor that performs the drop down binding
more easily.

Thank you for your help,

Brian
 

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