2005-06-21

Parent-Child combo boxes in C#.NET Windows Forms

I was fighting with a pretty simple scenario in a C#.NET Windows Forms project today. I was having trouble getting data binding to behave the way I wanted it to. I'm sure that other people have the same requirements in some of their apps: parent and child combo boxes.


  1. Bind controls on a form to a dataset called dsAddresses in this example. The parent and child SelectedValue are bound to CountryRegionID and StateProvinceID from this dsAddresses dataset.
  2. Populate the parent and child combo box items with data from country/region and states/provinces datasources (DataTables in this example) respectively
  3. When the parent combo box's selected value changes, have the items in the child combo box filtered automatically
This sounds pretty simple and like something that many of us would need to accomplish on a regular basis in both Windows Forms and ASP.NET Web Forms.
Well...I had a solution that was acceptable for the most part, but there was an few issue with the way that I implemented the solution.

Main issue: If you brought up the form and selected an address, the values in the parent and child combo boxes were bound to the correct values, but if you didn't select a country/region (which causes the SelectionChangeCommitted event to fire and this is where I called a method to filter the state/provinces manually in my previous solution) in the parent combo, the states/provinces combo would not be filtered and all states/provinces would show up.

I tried a number of workarounds and was about to scrap the entire original design of the form and start from scratch.

Brad Raulston gave me a hand and we tried a few things and then he researched it and found a blog posting by Andre King:

Parent-Child combo boxes in C#.NET Windows Forms

It detailed a scenario almost exactly like the one outlined above. I can't seem to get to the link at the moment but I was able to get the cached Google version.

Brad graciously helped me with the solution below:

Created a dataset called dsCountryState.
Merged 2 DataTables into it (because I already had them, but will refactor
to fill the dataset with both tables in one shot for efficiency later): one for
the parent Country/Region data and one for the State/Province data.

// Created a DataRelation for the parent and child DataTables like this:
DataRelation rel = new DataRelation("CountryStateRelation", dsCountryState.Tables["CountryRegion"].Columns["CountryRegionID"],
dsCountryState.Tables["StateProvince"].Columns["CountryRegionID"]);

// Accept Changes on the dsCountryState DataSet.
dsCountryState.AcceptChanges();

// parent combo bound to the
"parent_datatable.parent_column"cboCountryRegion.DataSource =
dsCountryState.Tables["CountryRegion"];

cboCountryRegion.DisplayMember = "CountryRegion.CountryRegionName";

cboCountryRegion.ValueMember = "CountryRegion.CountryRegionID";

// child combo bound to the "parent_datatable.parent_child_relation.child_column" cboStateProvince.DataSource = dsCountryState;

cboStateProvince.DisplayMember = "CountryRegion.CountryStateRelationship.StateProvinceName";

cboStateProvince.ValueMember = "CountryRegion.CountryStateRelationship.StateProvinceID";


What this accomplishes among other things is the combo boxes share
the same BindingManager which enables the required behavior. States/Provinces
are filtered automatically.

Thanks to Brad Raulston and Andre King for
the help and information. Hope this saves you some time and frustration.

No comments: