Design Question: onChange Event populating a second list box


Paul Hadfield

I'm looking for thoughts on the "correct" design for this problem (DotNet
2.0 - in winforms). I've got two combo boxes (combo1 and combo2), both are
populating via database calls (using a separate DB handler class). "combo1"
contains a list of countries and is fairly static, it can be added to but no
other external events cause a change in its population. "combo2" however is
populated with a list of options specific to a particular country. Changing
the selected item in "combo1" causes a refresh of the items listed in

In my solution, I've extended the ComboBox for "combo2", allowing it to
contain a reference to both "combo1" and the DB handler class (they are
passed to, not created in the extended ComboBox class (note "combo1" has
also been extended to contain a ref to the DB handler class and set itself
up from it). This has allowed me to attach the code that populates "combo2"
to the OnSelectedIndexChanged event of "combo1". It produces really nice
tight code, but I've just run into an issue that makes me think that I may
not have the best design (it's close but not quite). Basically the issue
is: how, if you persist the previous user selection, do you safely set up
the control(s) the second+ time that the user enters the form.

Pseudo-code of the issue:

combo1.DbHandler = dbh1; // Populates list with contents of dbh1
combo2.DbHandler = dbh2; // Assigns db2 to control, no list population
as no country selection yet.
combo2.CountryComboBox = combo1; // no have implied country selection,
and populates list accordingly
combo1.SelectedItem = UserSetting.cb1Value; // Changes selected
country, which fires updating of list in combo2

// I'm worried about this next line!
combo2.SelectedItem = UserSetting.cb2.Value; // Should set selected
option for previously selected country

I think in the above example, the line of code that tries to set the
selected item on combo2 could be run before, or at the same time as, the
event that updates combo2's list (triggered by setting the selected item in
combo1). Is this true, do triggered events run in parallel to the code that
triggered them? If so, what's the solution? Please note in the actual
form, I've got 4 copies of this user control and adding a country or option
in one of them, needs to update all the others - this is why the extended
combobox contains a reference to the (shared) db handler. The Create
function in the dbhandler fires an event that the extended combobox attaches
to. This in turn causes the list to update accordingly. I feel that I'm
not far from a MVC design pattern, and it may be the answer - but I don't
want to just end up moving the same problem out into another class.

Any thoughts, ideas or assistance would be much appreciated,

- Paul.




I am not sure whether this will serve your needs, but you can use a
DataRelation between two DataTables in a DataSet to cause a change in
one combobox to automatically adjust the choices in another combobox.
Here is a little sample showing how. Just drop a 2 comboboxes on a
form and add this form.Load.

private void Form1_Load(object sender, EventArgs e)
// Set up the DataSource - dataset with 2 datatables
DataTable countries = new DataTable("Countries");
countries.Columns.Add(new DataColumn("Country"));
DataRow dr = countries.NewRow();
dr[0] = "Great Britain";
dr = countries.NewRow();
dr[0] = "United States";

DataTable cities = new DataTable("Cities");
cities.Columns.Add(new DataColumn("Country"));
cities.Columns.Add(new DataColumn("City"));
dr = cities.NewRow();
dr[0] = "Great Britain";
dr[1] = "London";
dr = cities.NewRow();
dr[0] = "Great Britain";
dr[1] = "Reading";
dr = cities.NewRow();
dr[0] = "United States";
dr[1] = "New York";
dr = cities.NewRow();
dr[0] = "United States";
dr[1] = "Chicago";

DataSet ds = new DataSet();
ds.Tables.AddRange(new DataTable[] { countries, cities });
ds.Relations.Add(new DataRelation("CountriesToCities",
countries.Columns["Country"], cities.Columns["Country"]));

BindingContext fixedBindingContext = new BindingContext();

//setup the comboboxes
this.comboBox1.BindingContext = fixedBindingContext;
this.comboBox1.DataSource = countries;
this.comboBox1.DisplayMember = "Country";
this.comboBox1.ValueMember = "Country";

this.comboBox2.DataSource = countries;
this.comboBox2.BindingContext = fixedBindingContext;
this.comboBox2.DisplayMember = "CountriesToCities.City";
this.comboBox2.ValueMember = "CountriesToCities.City";

Clay Burch
Syncfusion, Inc.

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