c# - 绑定(bind)源的意外行为

标签 c# .net winforms bindingsource

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

使用 NET 4,通过 EntityFramework 4 读取 SQL 数据库,将结果写入存储在 BindingList 中的 ViewModel 列表,然后通过 BindingSource 绑定(bind)到 DataGridView。在 DataGridView 下,有各种字段,例如复选框、文本字段和组合框,它们绑定(bind)到与 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 绑定(bind)到 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 ,它们分别绑定(bind)到类型为 CountryCity 的 BindingSources,两个组合框的“DisplayMember”设置为“Name”,“ValueMember”设置为“ID”。 SelectedValuecmbCountry属性绑定(bind)到CountryIDcitizenViewModelBindingSource属性,SelectedValuecmbCity属性绑定(bind)到同一绑定(bind)源的CityID属性,所以组合框显示的值会根据在DGV中选择的项目而变化。

我正在处理 CurrentChangedcountryBindingSource 事件,它位于 cmbCountry 之后,因此当所选国家/地区发生更改时,cmbCity 会显示该所选国家/地区的城市。

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 的另一行,绑定(bind)源将神奇地分配与先前选择的行相同的 CityID国家ID。令人困惑?我将举例说明(并省略不相关的字段)。

Results:
1. Name: John Doe; Country: USA; City: Seattle
2. Name: John Smith; Country: Canada; City: Montreal
3. Name: Michael Owen; Country: England; City: Liverpool
4. Name: George Bush; Country: USA; City: Washington
5. Name: Vladimir Putin; Country: Russia; City: Moscow

选择 John Doe,组合框显示美国和西雅图。
选择 George Bush,组合框显示 USA 和 Washington。
选择 John Doe,组合框显示美国和西雅图。
选择 George Bush,组合框显示 USA 和 Washington。所以一切都还好。
选择 Michael Owen,组合框显示 England 和 Liverpool。
选择 John Doe,组合框显示美国和西雅图。
现在看这个。选择 George Bush,组合框显示 USA 和 Seattle(而不是它应该显示的 USA 和 Washington)。绑定(bind)源更改了乔治·布什的 CityID!

我已经写完了这个问题,但我还没有想到解决方案。为什么会发生这种情况以及如何避免这种行为?

编辑

通过解绑 cmbCity 的“SelectedValue”并修改 countryBindingSource_CurrentChanged 函数解决了这个问题:

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

但这对我来说似乎是一个 hack,如果有人知道为什么会发生这种情况,我将保留这个问题。

最佳答案

通过取消绑定(bind) cmbCity 的“SelectedValue”并手动设置 cmbCity.SelectedValue 解决了这个问题。通过像这样修改 countryBindingSource_CurrentChanged 函数来实现:

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

“我认为除了摆脱数据绑定(bind)你别无他法,因为在组合框具有数据绑定(bind)时更改其内容会修改绑定(bind)到 Selectedvalue 的属性,不管你喜不喜欢。” ——格特·阿诺德

关于c# - 绑定(bind)源的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16876806/

相关文章:

c# - 正则表达式替换 - 多个字符

javascript - .NET C# 使用 ExcelPackage 通过 JS post 导出到 excel

c# - 如何在 asp.net 中实现 "Add to clipboard"功能

c# - 尝试加载程序集 ID 65675 时 Microsoft .NET Framework 中发生错误

winforms - Windows 窗体的 UI 设计模式(如 WPF 的 MVVM)

C# DateTimePicker - 粗体日期?

winforms - 尝试在 C# 中使用 ActiveX 控件加载 PDF 文件时出现 COMException 错误

c# - WebAPI - 路由

c# - 如何启动包含引号的 URL?

c# - CS0436 共享项目的编译器警告