0

There are several posts here about DataGridViews that use a BindingSource and some DataGridViewComboBoxColumns, a.o:

However, these articles have a lot of details outside the problem, like SQL, DataSets, problems with automatic updating, etc.

I need a simple explanation about how to connect a DataGridView to a BindingSource where one (or more) column is a ComboBox filled with the available values. Preferably using the Visual Studio Designer.

As an example, I have classes Product and OrderLine:

class Product
{
    public int Id {get; set;}
    public string Description {get; set;}
    public decimal Price {get; set;}
}

public OrderLine
{
    public int Id {get; set;}
    public int ProductId {get; set;}
    public int Qty {get; set;}
}

I have a collection of available Products, and an order with a collection of OrderLines. How to design the DataGridView that it displays a ComboBox with descriptions of products instead of ProductId?

So how to do this using the designer?

Community
  • 1
  • 1
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116

1 Answers1

0

So we have two collections: products and order lines:

IEnumerable<Product> products = ...
IEnumerable<OrderLine> orderLines = ...

We have to create a DataGridView that displays all orderLines, but instead of the ProductId of each orderLine it has to display the description of the corresponding product.

After creating your form, use the designer to add a DataGridView and two BindingSources:

  • dataGridViewOrderLines will display the order lines.
  • bindingSourceOrderLines will be connected to orderLines
  • bindingSourceProducts be connect to products

Use the properties window to give them the proper names. Also change the following properties:

  • change property DataSource of bindingSourceProducts: right click the down arrow, and select Product as DataSource. If it is not there, select "Add project data source..."
  • in a similar way change DataSource of bindingSourceOrderLines to OrderLine
  • Set the DataSource of dataGridViewOrderLines to bindingSourceOrderLines.

The dataGridView in the form will automatically add columns for the properties of OrderLines. Instead of the product description we will see the ProductId as a text value. This has to change to a ComboBox that will show the description of the selected product. Under water it will have the correct ProductId.

To do this, go to the properties of the DataGridView and find property Columns in group Misc. If you open it, you'll see the collection of added columns.

On the left, select the column with ProductId. On the right change the following properties.

  • HeaderText: Product Description
  • ColumnType: DataGridViewComboBoxColumn

This means that the column should have a header Product Description. The column contains combo boxes.

Also change the following properties of the combo box column. Whenever possible use drop-down menus.

  • DataPropertyName: ProductId
  • DataSource: bindingSourceProducts
  • DisplayMember: Description
  • ValueMember: Id

This says, that the combo box should display values from the table in bindingSourceProducts (which are of type Product). From each record in this table display the value of property Description. So if you'd open the drop down of the Combo you'd see all Descriptions of all Products.

Furthermore it says that if you select a product Description, use Product.Id (as stated in ValueMember) as the selected value in OrderLine.ProductId (as stated in DataPropertyName).

Or the other way round: the displayed ProductId value of an OrderLine, will not be the ProductId, but the Description of the Product with the OrderLine.ProductId == Product.Id.

Now all you have to do is during run time connect to data sources to the collections to display. This must be done before the dataGridView is displayed, so probably during loading of the form:

public void OnLoadForm(object sender, EventArgs e)
{
    IEnumerable<Product> products = ...
    IEnumerable<OrderLine> orderLines = ...

    this.bindingSourceProducts.DataSource = products;
    this.bindingSourceOrderLines.DataSource = orderlines;
}

that from each element in the dataSource of the DataGridView (bindingSourceOrderLines), take the value of ProductId.

Then use this value to search in the table of the data source of bindingSourceProducts in the property Id (selected in ValueMember). If you find a matching record, take the value of

The items will be names dataGridViewOrderLines, bindingSourceOrderLines

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116