3

我并不总是将问题发布到 Stack Overflow,但当我这样做时,我通常会在完成发布问题之前找到解决方案。:-) 说真的,我遇到了我的 BindingSource 的奇怪行为,我找不到合乎逻辑的解释,我需要你的帮助。

使用 NET 4,通过 EntityFramework 4 读取 SQL 数据库,将结果写入存储在 BindingList 中的 ViewModel 列表,然后通过 BindingSource 绑定到 DataGridView。在 DataGridView 下有各种字段,例如复选框、文本字段和组合框,它们绑定到与 DataGridView 相同的 BindingSource。这样,当您从 DataGridView 中选择一个项目时,所有这些字段都将使用当前选定的 DataGridView 项目进行更新。

假设数据库中有两个表,它们的定义如下:

Table name: Country
-------------------
ID: integer, PK
Name: nvarchar

Table name: City
----------------
ID: integer, PK
CountryID: integer, FK to Country
Name: nvarchar

假设在一个名为“Citizen”的数据库中有一个表,定义如下:

Table name: Citizen
-------------------
ID: integer, PK
CityID: integer, FK to City
Name: nvarchar
... (and other irrelevant fields)

DataGridView 绑定到BindingList<CitizenViewModel>“CitizenViewModel”定义如下:

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;
    }
}

让我们命名 DGV 的 BindingSource citizenViewModelBindingSource

表单上有两个组合框cmbCountrycmbCity,它们分别绑定到 BindingSourcesCountryCitytype,两个组合框的“DisplayMember”设置为“Name”,“ValueMember”设置为“ID”。的SelectedValue属性cmbCountry绑定到的CountryID属性citizenViewModelBindingSourceSelectedValue属性cmbCity绑定到CityID同一个绑定源的属性,所以组合框显示的值会根据DGV中选择的项目而变化。

我正在处理其背后的CurrentChanged事件,因此当所选国家/地区发生更改时,会显示该所选国家/地区的城市。countryBindingSourcecmbCountrycmbCity

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);
}

问题如下:假设我的结果集有 5 行,其中 2 行 CountryID 相同但 CityID 不同,另外 3 行 CountryID 和 CityID 都不同。当我选择具有相同 CountryID 的两个项目之一,然后选择具有相同 CountryID 的另一个项目时,带有城市的组合框将相应更新。但是,如果我首先选择具有相同 CountryID 的这两个中的一个,然后选择具有不同 CountryID 的其中一个并最终选择具有相同 CountryID 的另一行,绑定源将神奇地分配与先前选择的具有相同的行相同的 CityID国家标识。令人困惑?我将用一个例子来解释(并省略不相关的字段)。

结果:
1. 姓名:John Doe;国家:美国;城市:西雅图
2。姓名:约翰·史密斯;国家:加拿大;城市:蒙特利尔
3. 姓名:迈克尔·欧文;国家:英国;城市:利物浦
4。姓名:乔治·布什;国家:美国;城市:华盛顿
5. 姓名:弗拉基米尔·普京;国家:俄罗斯;城市:莫斯科

Select John Doe, combo boxes say USA and Seattle.
Select George Bush, combo boxes say USA and Washington.
Select John Doe, combo boxes say USA and Seattle.
Select George Bush, combo boxes say USA and Washington. So everything is still fine.
Select Michael Owen, combo boxes say England and Liverpool.
Select John Doe, combo boxes say USA and Seattle.
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!

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?

EDIT

Solved the problem by unbinding the "SelectedValue" of cmbCity and modifying countryBindingSource_CurrentChanged function like this:

    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;
        }
    }

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.

4

1 回答 1

0

Solved the problem by unbinding the "SelectedValue" of cmbCity and setting the cmbCity.SelectedValue manually. Accomplished this by modifying countryBindingSource_CurrentChanged function like this:

    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;
        }
    }

"I think you can't do anything else but moving away from data binding because changing the content of a combobox while it has data binding modifies the property bound to Selectedvalue, like it or not." – Gert Arnold

于 2013-06-05T12:47:34.807 回答