Wpf ListBoxes List Items

Edited to refer to F Ruffell's answer

I have the following haml

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

and this code:

 var ints = new[] { 1, 2, 3 }; _list1.ItemsSource = ints; _list2.ItemsSource = ints; _list1.Items.Filter = i => ((int)i) < 2; 

For some reason, after setting the filter for only the first ListBox both lists are filtered . I expect lists to have completely different CollectionViews and even _list1.Items != _list2.Items . Meanwhile, installing a filter on one of them also somehow installs this filter on the other.
Question: why and how are CollectionViews synchronized?

+4
source share
3 answers

The question is why and how are CollectionViews synchronized?

They are synchronized because although both ListBoxes have different Items , they have the same CollectionView , which is the default view for the source collection.

The Items PropertyControl property is of the ItemCollection type, and the CollectionView ItemCollection property is internal, so we cannot access it directly to make sure this is true. However, we can simply enter these three values ​​in the debugger to check this, they all look like true

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

Alternatively, we can use reflection to compare in code.

 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); 

A way around this has already been published by F Ruffell, create a new ListCollectionView as an ItemsSource for each ListBox .

 _list1.ItemsSource = new ListCollectionView(ints); _list2.ItemsSource = new ListCollectionView(ints); 

Also note that after this 3 comparisons above come out as false

+4
source

When you set the ItemsSource , WPF actually creates a CollectionView from the specified IEnumerable . He does this so that there is the concept of the selected element (s), filtering, grouping, etc. (None of which are supported by IEnumerable assigned by ItemsSource ). When the same base collection is used more than once, WPF synchronizes two CollectionViews. If you don't want this behavior, just set IsSynchronizedWithCurrentItem to False on each ListBox .

For more information see

WPF Combobox Binding

Edit

Upon further investigation, it seems that setting IsSynchronizedWithCurrentItem really only applies to the selected item, and all other properties in the two ICollectionViews are still synchronized (although each ListBox has its own ICollectionView - changing Filter or adding a SortDescription to one, add it to another, you will recognize something new every day :)).

To change this behavior, you need to create an ICollectionView for each ListBox yourself, and then directly change the Filter property, for example:

  var ints = new[] { 1, 2, 3 }; var viewOne = new ListCollectionView(ints); var viewTwo = new ListCollectionView(ints); _list1.ItemsSource = viewOne; _list2.ItemsSource = viewTwo; viewOne.Filter = i => ((int)i) < 2; 

Hooray!

+7
source

Due to the reference type and providing both Listboxes with the same itemSource, if you manipulate one with the other, they will also be manipulated. If you want to achieve this, just use the new one and reassign the second list before submitting it to the ItemsSource.

0
source

All Articles