已编辑以解决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
同步?
答案 0 :(得分:7)
当您设置ItemsSource
WPF时,实际上会从指定的CollectionView
创建IEnumerable
。它这样做是为了有一个选定项目的概念,过滤,分组等(分配给IEnumerable
的{{1}}都不支持)。当多次使用相同的底层集合时,WPF将同步两个CollectionView。
如果您不想要这种行为,只需在每个ItemsSource
上将IsSynchronizedWithCurrentItem
设置为False
。
有关详细信息,请参阅:
修改强>
经过进一步调查后,似乎设置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。