Bound Combo Box Problems

G

Guest

I have what I think should be a simple question regarding a bound combo box.
My first table is Dealers:
DealerID - primary key
DealerName
BillToLocation

My second table is Locations:
LocationID - primary key
LocationDescription
DealerID - DealerID of the dealer this location belongs to

I want a bound combo box that when on a dealer record it displays the
LocationDescription for the dealer record's BillToLocation. But I want the
user to be able to change the BillToLocation to one of the dealers locations
in the Locations table.

At this point I have a combo box that shows only that Dealer's locations in
the drop down list, will update the BillToLocation when it's selected and
saved, but unfortunately it doesn't display correctly as I navigate through
the records using bmDealers.Position++ or bmDealers.Position--;
Interestingly enough, if I load a particular dealer record, it displays the
correct LocationDescription, but if navigate away and then back, it gets out
of sync.

Could someone give me some guidance as to what I'm doing wrong? Thank you.

Here is the binding code:
dsCoinTableAdapters.DealersTableAdapter daDealers = new
dsCoinTableAdapters.DealersTableAdapter();
dtDealers = ds.Dealers;
daDealers.Fill(dtDealers);

dsCoinTableAdapters.LocationsTableAdapter daLocations = new
dsCoinTableAdapters.LocationsTableAdapter();
dtLocations = ds.Locations;
daLocations.Fill(dtLocations);

DataColumn pdc = dtDealers.DealerIDColumn;
DataColumn cdc = dtLocations.DealerIDColumn;

DataRelation dr = new DataRelation("DealerToLocations", pdc, cdc);
ds.Relations.Add(dr);

bmDealers = this.BindingContext[ds, "Dealers"];

drDealer = dtDealers.FindByDealerID(nDealerID);
bmDealers.Position = dtDealers.Rows.IndexOf(drDealer);

txtDealerID.DataBindings.Add(new Binding("Text", ds,
"Dealers.DealerID"));
txtDealerName.DataBindings.Add(new Binding("Text", ds,
"Dealers.DealerName"));

cboBillToLocation.DataSource = ds;
cboBillToLocation.DisplayMember =
"Dealers.DealerToLocations.LocationDescription";
cboBillToLocation.ValueMember =
"Dealers.DealerToLocations.LocationID";
cboBillToLocation.DataBindings.Add(new Binding("SelectedValue",
ds, "Dealers.BillToLocation"));
 
G

Guest

Can anyone help here? It's pretty important and I can't find any examples
anywhere.

Thanks,

Bill
 
B

Bart Mermuys

Hi,

Bill said:
I have what I think should be a simple question regarding a bound combo
box.
My first table is Dealers:
DealerID - primary key
DealerName
BillToLocation

My second table is Locations:
LocationID - primary key
LocationDescription
DealerID - DealerID of the dealer this location belongs to

I want a bound combo box that when on a dealer record it displays the
LocationDescription for the dealer record's BillToLocation. But I want
the
user to be able to change the BillToLocation to one of the dealers
locations
in the Locations table.

At this point I have a combo box that shows only that Dealer's locations
in
the drop down list, will update the BillToLocation when it's selected and
saved, but unfortunately it doesn't display correctly as I navigate
through
the records using bmDealers.Position++ or bmDealers.Position--;
Interestingly enough, if I load a particular dealer record, it displays
the
correct LocationDescription, but if navigate away and then back, it gets
out
of sync.

Could someone give me some guidance as to what I'm doing wrong?

Problem :

The CurrencyManager (Dealers) maintains a position, when this position
changes then:
* the CurrencyManager will force all bindings to read value from datasource
to control,
* it will then fire CurrentItemChanged (among others), this event is handled
by:
- the RelatedCurrencyManager (Locations) and it will update the child
list.

So, SelectedValue is set *before* the child list is updated and updating a
child list causes a ListChanged(Reset) which makes the ComboBox always
select the first item. We need to get an event after the child list is
updated, then we can set SelectedValue.

This is possible by adding an eventhandler to
CurrencyManager.CurrentItemChanged after the RelatedCurrencyManager is
created (after binding to the child list).

See updated code:

CurrencyManager cmDealers;

private void FormLoad(...)
{
dsCoinTableAdapters.DealersTableAdapter daDealers = new
dsCoinTableAdapters.DealersTableAdapter();
dtDealers = ds.Dealers;
daDealers.Fill(dtDealers);

dsCoinTableAdapters.LocationsTableAdapter daLocations = new
dsCoinTableAdapters.LocationsTableAdapter();
dtLocations = ds.Locations;
daLocations.Fill(dtLocations);

DataColumn pdc = dtDealers.DealerIDColumn;
DataColumn cdc = dtLocations.DealerIDColumn;
ds.Relations.Add("DealerToLocations", pdc, cdc);

// bm is really a CurrencyManager
cmDealers = (CurrencyManager) this.BindingContext[ds, "Dealers"];

cmDealers.Position =
((IBindingList)cmDealers.List).Find(cmDealers.GetItemProperties().Find("DealerID",
false), nDealerID);

// binding parent list
txtDealerID.DataBindings.Add("Text", ds, "Dealers.DealerID");
txtDealerName.DataBindings.Add("Text", ds, "Dealers.DealerName"));

// binding child list
cboBillToLocation.DataSource = ds;
cboBillToLocation.DisplayMember =
"Dealers.DealerToLocations.LocationDescription";
cboBillToLocation.ValueMember = "Dealers.DealerToLocations.LocationID";

cboBillToLocation.DataBindings.Add("SelectedValue", ds,
"Dealers.BillToLocation");

// after binding the child list
cmDealers.CurrentItemChanged+= new EventHandler(
cmDealers_CurrentItemChanged );
}

private void cmDealers_CurrentItemChanged(object sender, EventArgs e)
{
// because we subscribed to this event *after binding to the child list*,
this
// will be invoked after the child list is updated, read the value from
source
cboBillToLocation.DataBindings["SelectedValue"].ReadValue();
}


HTH,
Greetings
 
G

Guest

Bart,

Thank you so much. This will be a big help. I had conceded to coding a
klunky workaround, so this will be much better.

Thanks again,

Bill

Bart Mermuys said:
Hi,

Bill said:
I have what I think should be a simple question regarding a bound combo
box.
My first table is Dealers:
DealerID - primary key
DealerName
BillToLocation

My second table is Locations:
LocationID - primary key
LocationDescription
DealerID - DealerID of the dealer this location belongs to

I want a bound combo box that when on a dealer record it displays the
LocationDescription for the dealer record's BillToLocation. But I want
the
user to be able to change the BillToLocation to one of the dealers
locations
in the Locations table.

At this point I have a combo box that shows only that Dealer's locations
in
the drop down list, will update the BillToLocation when it's selected and
saved, but unfortunately it doesn't display correctly as I navigate
through
the records using bmDealers.Position++ or bmDealers.Position--;
Interestingly enough, if I load a particular dealer record, it displays
the
correct LocationDescription, but if navigate away and then back, it gets
out
of sync.

Could someone give me some guidance as to what I'm doing wrong?

Problem :

The CurrencyManager (Dealers) maintains a position, when this position
changes then:
* the CurrencyManager will force all bindings to read value from datasource
to control,
* it will then fire CurrentItemChanged (among others), this event is handled
by:
- the RelatedCurrencyManager (Locations) and it will update the child
list.

So, SelectedValue is set *before* the child list is updated and updating a
child list causes a ListChanged(Reset) which makes the ComboBox always
select the first item. We need to get an event after the child list is
updated, then we can set SelectedValue.

This is possible by adding an eventhandler to
CurrencyManager.CurrentItemChanged after the RelatedCurrencyManager is
created (after binding to the child list).

See updated code:

CurrencyManager cmDealers;

private void FormLoad(...)
{
dsCoinTableAdapters.DealersTableAdapter daDealers = new
dsCoinTableAdapters.DealersTableAdapter();
dtDealers = ds.Dealers;
daDealers.Fill(dtDealers);

dsCoinTableAdapters.LocationsTableAdapter daLocations = new
dsCoinTableAdapters.LocationsTableAdapter();
dtLocations = ds.Locations;
daLocations.Fill(dtLocations);

DataColumn pdc = dtDealers.DealerIDColumn;
DataColumn cdc = dtLocations.DealerIDColumn;
ds.Relations.Add("DealerToLocations", pdc, cdc);

// bm is really a CurrencyManager
cmDealers = (CurrencyManager) this.BindingContext[ds, "Dealers"];

cmDealers.Position =
((IBindingList)cmDealers.List).Find(cmDealers.GetItemProperties().Find("DealerID",
false), nDealerID);

// binding parent list
txtDealerID.DataBindings.Add("Text", ds, "Dealers.DealerID");
txtDealerName.DataBindings.Add("Text", ds, "Dealers.DealerName"));

// binding child list
cboBillToLocation.DataSource = ds;
cboBillToLocation.DisplayMember =
"Dealers.DealerToLocations.LocationDescription";
cboBillToLocation.ValueMember = "Dealers.DealerToLocations.LocationID";

cboBillToLocation.DataBindings.Add("SelectedValue", ds,
"Dealers.BillToLocation");

// after binding the child list
cmDealers.CurrentItemChanged+= new EventHandler(
cmDealers_CurrentItemChanged );
}

private void cmDealers_CurrentItemChanged(object sender, EventArgs e)
{
// because we subscribed to this event *after binding to the child list*,
this
// will be invoked after the child list is updated, read the value from
source
cboBillToLocation.DataBindings["SelectedValue"].ReadValue();
}


HTH,
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