WPF:绑定的ItemSource集合发生更改后,Combobox会失去所选索引

7
我在Google和这里搜索了答案,我的问题与下面的问题有些相关,但不同到足以提出新问题。
基本上,我有一个绑定到ObservableCollection类的WPF组合框。如果需要对其进行多次修改(例如清除并重新填充以获取数据库的新快照),则此类具有延迟集合更改通知的额外功能。
我的组合框绑定同时设置了DisplayMemberPath和SelectedValuePath。 SelectedValuePath解析为整数属性。
问题与引用问题相同,当我刷新绑定集合中的值时,绑定的ComboBox会失去其选择,并变为空白(SelectedIndex = -1)。
我可以确认,直到集合重新填充并再次包含项目之前,CollectionChanged事件不会触发。
更令人困惑的是,如果我执行以下操作:
        using (_collection.DelayNotifications())
        {
            var items = _collection.ToArray();
            _collection.Clear();
            _collection.AddRange(items);
        }

下拉框不会失去其选定的值。

这表明,如果集合中的项被替换为从数据库检索的新项,则会出现问题——如果我不使用SelectedValuePath绑定,我可以接受这一点,但因为我正在使用它,并且整数值相同,所以我做的事情肯定应该起作用吧?

我正在使用.NET 3.5 SP1。

有人有什么想法吗?

编辑

根据下面的评论和Blam的答案。我确实接受那些是它这样做的原因。但这并没有真正帮助我。

我将Combobox的SelectedValue属性绑定到我的视图模型上的一个整数属性。如果我要绑定SelectedItem,我需要绑定到我的视图模型上的那个对象类型的属性,但实际上我想要的是整数属性。

目前,我通过强制触发与'SelectedValue'绑定的属性更改事件来“修复”(读取较小的黑客)此问题。这似乎使下拉框重新检查其内部列表,以查找与定义的SelectedValuePath匹配的项。

WPF Combobox必须“知道”它已设置SelectedValuePath值,因此我认为它会调整其项目匹配逻辑。但是这超出了SO的范围。我意识到我可能只能接受这就是WPF的工作方式,但在WinForms中与数据绑定的comboboxes斗争了几年后,我有点希望不必在WPF中这样做:尽管如此,WPF Combobox比WinForm Combobox更好。

ValuePath并不重要,即使是不同的对象...你不能期望绑定会保持,因为它绑定到特定的实例(对象)。一旦你移除了它们,绑定就丢失了... - UIlrvnd
DelayNotificatons() 返回的对象的处理方法会Raise CollectionChange事件并带有ListReset标记。我仍然会假设ComboBox会查找其新列表中可以匹配的整数值... 如果这不是发生的情况,我的选择是什么? - Marlon
在你的代码示例中,你使用相同的实例,因为你操作的唯一东西是集合。即使整数具有相同的值,它看起来也不同,因为它是一个不同的实例...希望这有意义哈哈... - UIlrvnd
绑定到选定项。重写gethashcode和equals方法,以使新的SelectedItem与旧的相同。 - paparazzo
或者你可以自行比较并设置它... - UIlrvnd
看一下这个:http://stackoverflow.com/questions/16469194/combobox-sourceupdated-event-is-not-fired - Arian Motamedi
1个回答

4

这个说法是错的

如果我没有使用SelectedValuePath绑定,那么我可以接受这个说法,但是因为我在使用

你并没有绑定到SelectedValuePath。
你正在绑定到一组对象。
SelectedValuePath只是用于报告与比较对象相等无关的内容。 DisplayMemberPath只是用于报告,与比较对象是否相等无关。

你将SelectValuePath与SelectedItem混淆了。
ComboBox不使用SelectedValuePath来确定两个对象是否相等。

从SelectedValuePath的文档中可以得知:

获取或设置用于从SelectedItem中获取SelectedValue的路径。

在使您困惑的示例中,您会重新加载相同的对象。

我假设SelectedValuePath是一个名为ID的属性

如果您清除并重新创建一个ID为6的对象,则它与具有ID为6的已清除对象不相等。

请尝试这个。 创建两个ID为6的对象(o1和o2),并比较o1.Equals(o2)。

如果您希望具有ID为6的两个对象相等,则需要覆盖GetHashCode和Equals。 在Equals中,如果两个对象都具有ID为6,则返回true。而且您可以使用ID作为GetHashCode。

字符串是一个将会让你困惑的引用类型。
string s1 = "cat";
string s2 = "cat";
s1.Equals(s2)将返回true,因为String Equals被覆盖为比较值。


是的,我理解这一点,但我绑定的是SelectedValue,而不是SelectedItem。因此,我不希望ComboBox在SelectedItem上进行相等比较。虽然我猜它无法确定某人已经绑定了哪些属性,并调整其内部逻辑以适应。 - Marlon
正如我在回答中所述,并由Stefen在评论中指出,您并没有绑定到SelectedValue。您正在绑定到对象集合。DisplayMemberPath和SelectedValuePath仅用于报告。这就是答案。为什么您要拒绝它而不是应用它呢? - paparazzo
我并不是在拒绝它 - 我只是在解释我正在做什么。我认为我的逻辑并不是那么没有根据的。请看我对问题的编辑。我会再给它几天,但我很可能会接受你的答案。 - Marlon
但是原生的ComboBox绑定到一个对象集合并使用对象相等。视图模型是注入自身的一层。 - paparazzo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接