为啥我需要手动更新绑定的组合框?

Posted

技术标签:

【中文标题】为啥我需要手动更新绑定的组合框?【英文标题】:Why do I need to update a bound combobox manually?为什么我需要手动更新绑定的组合框? 【发布时间】:2019-04-18 07:18:17 【问题描述】:

我的设置

我有以下(伪)EF 类:

class Department 
    int ID,
    string Name


class DepartmentCustomer 
    int ID,
    int CustomerID,
    Customer Customer,
    string Information,
    int DepartmentID,
    Department Department


Class Customer 
    int ID,
    string Name,
    int? CityID,
    City City


Class City
    int ID,
    string Name,
    string PostalCode

我有一个带有 List(of DepartmentCustomer) 的 BindingSource 和以下字段的表单:

DepartmentCustomer.Information 作为(读写)文本框 DepartmentCustomer.Customer.Name 作为(只读)文本框 DepartmentCustomer.Customer.City 作为(读写)组合框。

城市名称的组合框具有以下属性:

ComboBoxCity.DataSource = ListOfCities  ' = List(Of City)
ComboBoxCity.ValueMember = "Id"
ComboBoxCity.DisplayMember = "Name"
ComboBoxCity.DataBindings.Add(New Binding("SelectedItem", DepartmentCustomerBindingSource, "Customer.City", True, DataSourceUpdateMode.OnPropertyChanged))

我的问题

DepartmentCustomerBindingSource.CurrentItemChanged出现时,Combobox不同步;它有时会更新为正确的值,但是当进一步浏览 BindingSource 时,它​​会保持上一个项目被选中

所以,我必须手动更新组合框

Private Sub DepartmentCustomerBindingSource_CurrentItemChanged(sender As Object, e As EventArgs) Handles DepartmentCustomerBindingSource.CurrentItemChanged
    If DepartmentCustomerBindingSource.Current.Contact.City Is Nothing then
        ComboBoxCity.SelectedIndex = -1
    Else
        ComboBoxCity.SelectedItem = DepartmentCustomerBindingSource.Current.Contact.City
    End if
End Sub

(为了简单起见,我在上面的代码中省略了强制转换。此外,这些示例类可能没有意义 IRL)

编辑

即使上面的代码也不能满足我的要求。 例如:我有两个 DepartmentCustomer 实例,一个带有 Contact.City,第二个没有 Contact.City。当表单第一次打开时,它会显示城市;当我导航到第二条记录时,组合框变为空,但是当我回到第一个组合框时,它保持为空;更令人惊讶的是,第一条记录已经更新为 Contact.City = Nothing :'(

编辑 2:我自己不喜欢的解决方案

我已从组合框 (ComboBoxCity.DataBindings.Add(New Binding("SelectedItem", DepartmentCustomerBindingSource, "Customer.City", True, DataSourceUpdateMode.OnPropertyChanged))) 中删除了数据绑定并添加了以下子项

Private Sub ComboBoxCity_SelectedValueChanged(sender As Object, e As EventArgs) Handles ComboBoxCity.SelectedValueChanged
    DepartmentCustomerBindingSource.Current.Contact.City = ComboBoxCity.SelectedItem
End Sub

这行得通,但是由于我的表单中有很多这样的组合框,我认为必须有一种“自动”的方式来同步双向绑定的组合框...

编辑 3:我认输

即使我上面的“解决方案”也没有按预期工作;使用上述代码时,实例的 Contact.City 未正确更新...

我的问题

为什么我必须手动执行此操作;我错过了什么吗?我认为通过设置 DataBinding,只要导航绑定的 BindingSource,它就会更新 SelectedItem;

【问题讨论】:

大多数情况下,控件不更新是与接口 INotifyPropertyChanged 和 IBinding​List 未(正确)实现相关的问题。 @MarcoGuignard 谢谢!!!请参阅下面的答案(以及我的附加问题) 【参考方案1】:

ComboBox 数据绑定到 SelectedItem 属性和 null (Nothing) 源值似乎存在问题(错误?)。

从另一端绑定到SelectedValue 没有这样的问题。所以解决方案/解决方法是绑定到SelectedItem 以更新数据源并绑定到SelectedValue 以更新控件:

ComboBoxCity.DataBindings.Add(New Binding("SelectedItem", DepartmentCustomerBindingSource, "Customer.City", True, DataSourceUpdateMode.OnPropertyChanged))    
ComboBoxCity.DataBindings.Add(New Binding("SelectedValue", DepartmentCustomerBindingSource, "Customer.City.ID", True, DataSourceUpdateMode.Never))

【讨论】:

真的吗?那看起来很疯狂。也许有任何参考资料? 参考?你一定是在开玩笑 :) 反复试验。【参考方案2】:

大多数情况下,控件不更新是与接口 INotifyPropertyChanged 和 IBinding​List 未(正确)实现相关的问题。 ——马可·吉纳德

这让我想到:我确实在使用以下内容来填充 DepartmentCustomerBindingSource

DepartmentCustomerBindingSource.DataSource = DBContext.DepartmentCustomer.Local.ToList

将其更改为

DepartmentCustomerBindingSource.DataSource = DBContext.DepartmentCustomer.Local.ToBindingList

它有效:-/

但是,当将数据源设置为特定记录而不是(绑定)列表时,如何使其正常工作?

DepartmentCustomerBindingSource.DataSource = DBContext.DepartmentCustomer.Local.First

【讨论】:

将 INotifyPropertyChanged 的​​实现添加到 DepartmentCustomer 类 docs.microsoft.com/en-us/dotnet/api/… 顺便说一句,您最好使用 ForeignKey 属性来做组合框的选定值之间的链接 @MarcoGuignard 我不知道为什么以及如何这样做。每个想要使用 Combobox 来更新 EF POCO 的人都必须实现这个吗? 在组合框上,将数据源设置为城市集合(如果不更新城市列表,列表就足够了),将 DisplayMember 设置为 Name,将 ValueMember 设置为 ID。然后在组合框的 SelectedValue 和包含客户的 BindingSource 的 CityID 属性之间设置绑定。【参考方案3】:

经过多次反复试验,我找到了以下解决方案:

考虑以下代码:

ComboBoxCity.DataSource = ListOfCities  ' = List(Of City)
ComboBoxCity.ValueMember = "Id"
ComboBoxCity.DisplayMember = "Name"
ComboBoxCity.DataBindings.Add(New Binding("SelectedItem", DepartmentCustomerBindingSource, "Customer.City", True, DataSourceUpdateMode.OnPropertyChanged))

让我前进的事情是将 ComboBoxCity.DataSource 设置为实现 IBindingList 的类型,如下所示:

DBContext.Cities.Load
CitiesBindingSource.DataSource = DBContext.Cities.Local.ToBindingList
ComboBoxCity.DataSource = CitiesBindingSource

因此,绑定数据(在本例中为 DepartmentCustomerBindingSource)必须是 BindingList,而只有 Datasource 必须实现 IBindingSource...

【讨论】:

以上是关于为啥我需要手动更新绑定的组合框?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的组合框无法绑定到 ViewModel 中的 List<string>? WPF

在 aspxgridview 中绑定与另一个组合框关联的组合框

在摇摆中绑定组合框

MS Access 2010:未绑定的组合框不会更新

DataGrid 数据绑定/更新中的 WPF 组合框不起作用

MS Access:为啥我的组合框显示错误的值?