Note that there are some explanatory texts on larger screens.

plurals
  1. POUnexpected behavior of binding source
    primarykey
    data
    text
    <p>I don't always post a problem to Stack Overflow, but when I do, I usually find the solution before I finish posting the problem. :-) Seriously now, I am experiencing a weird behavior of my BindingSource, I can't find a logical explanation for it and I need your help.</p> <p>Using NET 4, reading a SQL database through EntityFramework 4, writing results to a list of ViewModels which are stored in a BindingList, which is then bound to a DataGridView via BindingSource. Under the DataGridView there are various fields such as check boxes, text fields and combo boxes bound to the same BindingSource as the DataGridView. That way, when you select an item from a DataGridView all those fields are updated with the currently selected DataGridView item.</p> <p>Let's say there are two tables in a database which are defined like this:</p> <pre><code>Table name: Country ------------------- ID: integer, PK Name: nvarchar Table name: City ---------------- ID: integer, PK CountryID: integer, FK to Country Name: nvarchar </code></pre> <p>Let's also say there is a table in a database called "Citizen" defined like this:</p> <pre><code>Table name: Citizen ------------------- ID: integer, PK CityID: integer, FK to City Name: nvarchar ... (and other irrelevant fields) </code></pre> <p>The DataGridView is bound to a <code>BindingList&lt;CitizenViewModel&gt;</code> where "CitizenViewModel" is defined like this:</p> <pre><code>class CitizenViewModel { public int ID { get; set; } public int CityID { get; set; } public string Name { get; set; } public int CountryID { get; set; } public CitizenViewModel(Citizen c) { this.ID = c.ID; this.CityID = c.CityID; this.Name = c.Name; this.CountryID = c.City.CountryID; } } </code></pre> <p>Let's name the DGV's BindingSource <code>citizenViewModelBindingSource</code>.</p> <p>There are two combo boxes on the form, <code>cmbCountry</code> and <code>cmbCity</code>, both bound to BindingSources of <code>Country</code> and <code>City</code> type respectively, with "DisplayMember" set to "Name" and "ValueMember" set to "ID" for both combo boxes. The <code>SelectedValue</code> property of <code>cmbCountry</code> is bound to the <code>CountryID</code> property of <code>citizenViewModelBindingSource</code> and the <code>SelectedValue</code> property of <code>cmbCity</code> is bound to <code>CityID</code> property of the same binding source, so the combo box displayed value changes according to the item selected in DGV.</p> <p>I am handling the <code>CurrentChanged</code> event of <code>countryBindingSource</code> which is behind the <code>cmbCountry</code> so when the selected country is changed, <code>cmbCity</code> displays cities of that selected country.</p> <pre><code>private void countryBindingSource_CurrentChanged(object sender, EventArgs e) { // Get the list of Cities that belong to the selected Country cityBindingSource.DataSource = GetCities(((Country)countryBindingSource.Current).ID); } </code></pre> <p>The problem is as follows: let's say my result set has got 5 rows, where 2 of them have the same CountryID but different CityID, and the other 3 have all different CountryIDs and CityIDs. When I select one of the two items with the same CountryID and then select the other one with the same CountryID, the combo box with cities will update accordingly. However if I first select one of these two with the same CountryID, then select one of those with different CountryID and eventually select the other row with the same CountryID, the binding source will magically assign the same CityID as the previously selected row with the same CountryID. Confusing? I will explain with an example (and omit irrelevant fields).</p> <blockquote> <p>Results:<br> 1. Name: John Doe; Country: USA; City: Seattle<br> 2. Name: John Smith; Country: Canada; City: Montreal<br> 3. Name: Michael Owen; Country: England; City: Liverpool<br> 4. Name: George Bush; Country: USA; City: Washington<br> 5. Name: Vladimir Putin; Country: Russia; City: Moscow </p> </blockquote> <p>Select John Doe, combo boxes say USA and Seattle.<br> Select George Bush, combo boxes say USA and Washington.<br> Select John Doe, combo boxes say USA and Seattle.<br> Select George Bush, combo boxes say USA and Washington. So everything is still fine.<br> Select Michael Owen, combo boxes say England and Liverpool.<br> Select John Doe, combo boxes say USA and Seattle.<br> Now watch this. Select George Bush, combo boxes say USA and Seattle (not USA and Washington as it should). The binding source has changed the CityID of George Bush!</p> <p>I have finished writing about the problem but the solution hasn't come to my mind. Why is this happening and how to avoid this behavior? </p> <p><strong>EDIT</strong></p> <p>Solved the problem by unbinding the "SelectedValue" of <code>cmbCity</code> and modifying <code>countryBindingSource_CurrentChanged</code> function like this:</p> <pre><code> private void countryBindingSource_CurrentChanged(object sender, EventArgs e) { if (citizenViewModelBindingSource.Current != null) { cityBindingSource.DataSource = GetCities(((Country)countryBindingSource.Current).ID); // update the combo box manually cmbCity.SelectedValue = ((CitizenViewModel)citizenViewModelBindingSource.Current).CityID; } } </code></pre> <p>But this seems like a hack to me and I will keep this question open if anyone has got a clue on why this would happen.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload