如何在将对象分配为其SelectedItem时更新WPF ComboBox?
如何在将对象分配为其SelectedItem时更新WPF ComboBox?
我有一个ComboBox,它的ItemsSource绑定到一个ObservableCollection
示例类:
public class CustomObject : INotifyPropertyChanged
{
public string Property1 { /*...省略...*/ }
public string Property2 { /*...省略...*/ }
public string Property3 { /*...省略...*/ }
}
我的ComboBox的SelectedItem属性绑定到出现在DataGrid行中的CustomObject属性。
示例类:
public class DataGridEntry : INotifyPropertyChanged
{
public CustomObject Column1 { /*...省略...*/ }
public string Column2 { /*...省略...*/ }
public string Column3 { /*...省略...*/ }
}
我在窗口初始化期间创建了ObservableCollection
我的目标是加载初始值到我的DataGrid中,但我不知道如何让ComboBox意识到指定的CustomObject可以在其ItemsSource中找到,并且因此ComboBox不会渲染SelectedItem。
以下是我加载初始值的方式:
ObservableCollection
MyWindow.DataContext = this;
entries.Add(new DataGridEntry(new CustomObject("val1", "val2", "val3"), "col2", "col3");
你知道我如何使ComboBox设置其SelectedItem属性吗?如果我更改代码,使DataGridEntry仅与字符串属性配合工作,那么ComboBox在初始化后按预期渲染SelectedItem。对于引用类型,它却不起作用。
如果需要,这是我将数据绑定到ComboBox的方式:
编辑:
如果不清楚,ObservableCollection
我怀疑ComboBox没有意识到这两个CustomObject是等效的。因为这个怀疑,我重写了CustomObject的Equals和GetHashCode函数,但没有成功。显然,ComboBox对于字符串等非引用数据类型可以很好地检测到相等性。
谢谢帮助! 🙂
问题的原因是WPF的ComboBox使用Object.Equals方法来确定相等性。默认情况下,当处理引用类型时,ComboBox期望的是相同的引用。而当处理值类型时,Object.Equals会比较值。虽然String技术上不是值类型,但它重写了Object.Equals方法来比较值。
类似于String,可以通过为ComboBox所持有的类类型定义自定义的Equals方法来覆盖相等性行为。
在原始帖子的示例中,Equals方法应该比较每个属性,如下所示:
public class CustomObject : INotifyPropertyChanged { //包括属性、构造函数和INotifyPropertyChanged接口成员。 public override bool Equals(object obj) { CustomObject test = obj as CustomObject; //如果obj无法转换,则test=null。 if(test == null) return false; //将null与非null进行比较:FALSE else { //检查所有属性是否相等。 return ((Property1.CompareTo(test.Property1) == 0) && (Property2.CompareTo(test.Property2) == 0) && (Property3.CompareTo(test.Property3) == 0)); } } }
尽管ComboBox在没有这个方法的情况下仍然可以正常工作,但最好也覆盖Object.GetHashCode方法。这超出了本回答的范围,但是可以在这里找到一个文档完善的实现:
https://stackoverflow.com/a/263416/975724
理想情况下,你应该在else语句之前实现Object.Equals方法。然后,在这个点上,你可以调用IEquatable.Equals方法,因为你提供的实现是特定于类型的,正如IEquatable在MSDN上的文档所说:“定义了一个通用方法,值类型或类实现它来创建用于确定实例相等性的类型特定方法。”
请详细说明一下。如果我只是将我的else块移动到IEquatable.Equals中,并从Object.Equals中调用IEquatable.Equals,那么除了类型转换和空值检查外,这两者是相同的。我不太确定这样做有什么作用,因为ComboBox不关心IEquatable.Equals。这与扩展我的类有关吗?
不,这与Object.Equals不应该是特定于类型的实现有关,而IEquatable.Equals是特定于类型的。你可以将其视为样式偏好,但我喜欢将代码分开,以便类型不特定的方法实际上是类型不特定的(因为文档中建议以这种方式使用)。另外,一旦你确定对象是相同类型,从类型不特定的Object.Equals中调用特定于类型的IEquatable.Equals没有问题。
解决方法就是在ComboBox所持有的类类型中实现自定义的Equals方法,并在Object.Equals中调用IEquatable.Equals方法。这样可以确保ComboBox在比较SelectedItem时正确工作。
问题的出现原因是在WPF中,当将一个对象赋值给ComboBox的SelectedItem属性时,ComboBox无法正确更新。这是因为ComboBox默认使用Equals方法来比较对象,而Equals方法在Object类型上进行比较。所以,如果要在ComboBox中正确比较对象,需要实现IEquatable接口。
解决方法是在对象类中实现IEquatable接口,并重写Equals方法。通过重写Equals方法,可以定义对象之间的比较规则。例如,可以只比较对象的某个属性,而不是整个对象。这样,在ComboBox中赋值对象给SelectedItem属性时,ComboBox就可以正确比较对象。
在解决问题之后,还发现了绑定属性名错误的问题。在修复绑定问题后,测试发现只使用Object.Equals方法也能正确更新ComboBox。但是,IEquatable.Equals方法可以更准确地进行类型比较。
总之,通过实现IEquatable接口并重写Equals方法,可以解决在WPF中将对象赋值给ComboBox的SelectedItem属性时无法正确更新的问题。这种解决方法可以根据不同的类进行定制,并且将代码集中在影响的类中。这种解决方法在2017年仍然有效,并且可以解决一些旧版本的WPF或EF中的相等性处理问题。