为啥我需要手动更新绑定的组合框?
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 和 IBindingList 未(正确)实现相关的问题。 @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 和 IBindingList 未(正确)实现相关的问题。 ——马可·吉纳德
这让我想到:我确实在使用以下内容来填充 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 中绑定与另一个组合框关联的组合框