Wpf ListBoxes的ItemsSource奇怪的行为

时间:2011-10-10 13:43:32

标签: .net wpf .net-4.0

已编辑以解决F Ruffell's answer

我有以下xaml

<StackPanel>
    <ListBox x:Name="_list1"/>
    <ListBox x:Name="_list2"/>
</StackPanel>

和这个代码隐藏:

var ints = new[] { 1, 2, 3 };
_list1.ItemsSource = ints;
_list2.ItemsSource = ints;

_list1.Items.Filter = i => ((int)i) < 2;

出于某种原因,仅为第一个ListBox 设置过滤器后,两个列表都会被过滤。我希望列表具有完全不同的CollectionViews_list1.Items != _list2.Items。同时设置过滤器到其中一个也以某种方式设置过滤到另一个。
问题是为什么 CollectionViews同步?

3 个答案:

答案 0 :(得分:7)

当您设置ItemsSource WPF时,实际上会从指定的CollectionView创建IEnumerable。它这样做是为了有一个选定项目的概念,过滤,分组等(分配给IEnumerable的{​​{1}}都不支持)。当多次使用相同的底层集合时,WPF将同步两个CollectionView。 如果您不想要这种行为,只需在每个ItemsSource上将IsSynchronizedWithCurrentItem设置为False

有关详细信息,请参阅:

WPF Combobox binding

修改

经过进一步调查后,似乎设置ListBox实际上仅适用于所选项目,并且两个IsSynchronizedWithCurrentItem中的所有其他属性仍然同步(即使每个ICollectionViews都有拥有ListBox - 更改ICollectionView或将Filter添加到一个,将其添加到另一个,您每天都会学到新东西:))。

要更改此行为,您需要自己为每个SortDescription创建ICollectionView,然后直接修改ListBox属性,例如:

Filter

干杯!

答案 1 :(得分:4)

  

问题是CollectionViews为何以及如何同步?

它们是同步的,因为即使两个ListBoxes都有不同的Items,它们也会共享相同的CollectionView,这是源集合的默认视图。

Items的{​​{1}}属性属于ItemsControl类型,ItemCollection CollectionView属性为内部,因此我们可以不要直接访问它来验证这是真的。但是,我们可以在调试器中输入这三个值来验证这一点,它们都是真的

ItemCollection

或者,我们可以使用反射在代码中进行比较

_list1.Items.CollectionView == _list2.Items.CollectionView // true
_list1.Items.CollectionView == CollectionViewSource.GetDefaultView(ints) // true
_list2.Items.CollectionView == CollectionViewSource.GetDefaultView(ints) // true

F Ruffell 已经发布了解决此问题的方法,为每个PropertyInfo collectionViewProperty = typeof(ItemCollection).GetProperty("CollectionView", BindingFlags.NonPublic | BindingFlags.Instance); ListCollectionView list1CollectionView = collectionViewProperty.GetValue(_list1.Items, null) as ListCollectionView; ListCollectionView list2CollectionView = collectionViewProperty.GetValue(_list2.Items, null) as ListCollectionView; ListCollectionView defaultCollectionView = CollectionViewSource.GetDefaultView(ints) as ListCollectionView; Debug.WriteLine(list1CollectionView == list2CollectionView); Debug.WriteLine(list1CollectionView == defaultCollectionView); Debug.WriteLine(list2CollectionView == defaultCollectionView); 创建一个新的ListCollectionView ItemsSource

ListBox

还要注意,在此之后,上述3次比较显示为假

答案 2 :(得分:0)

由于引用类型并且如果您操纵另一个,则同时为两个Listbox提供相同的itemSource也将被操纵。如果你想获得这个,只需使用new并重新分配第二个列表框,然后再将它提供给ItemsSource。