WPF ListBoxes 'ItemsSource странное поведение - PullRequest
4 голосов
/ 10 октября 2011

Отредактировано по адресу F Ответ Руффелла

У меня есть следующий 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 ]

7 голосов
/ 10 октября 2011

Когда вы устанавливаете ItemsSource WPF фактически создает CollectionView из указанного IEnumerable.Он делает это так, что существует понятие выбранного элемента (ов), фильтрации, группировки и т. Д. (Ни один из которых не поддерживается IEnumerable, назначенным для ItemsSource).Когда одна и та же базовая коллекция используется более одного раза, WPF синхронизирует два CollectionView.Если вам не нужно это поведение, просто установите IsSynchronizedWithCurrentItem на False для каждого ListBox.

Для получения дополнительной информации см .:

Связывание WPF Combobox

Редактировать

При дальнейшем исследовании создается впечатление, что настройка IsSynchronizedWithCurrentItem действительно применяется только к выбранному элементу, а все остальные свойства в этих двух ICollectionViews по-прежнемусинхронизировано (даже если у каждого ListBox есть свой ICollectionView - при изменении Filter или добавлении SortDescription к одному добавится к другому, вы узнаете что-то новое каждый день :)).

Чтобы изменить это поведение, вам нужно создать ICollectionView для каждого ListBox самостоятельно, а затем напрямую изменить свойство Filter, например:

        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;

Cheers!

4 голосов
/ 15 октября 2011

Вопрос в том, почему и как синхронизируются CollectionViews?

Они синхронизированы, потому что, хотя оба ListBoxes имеют разные Items, они совместно используют один и тот же CollectionView, который является видом по умолчанию для исходной коллекции.

Свойство Items ItemsControl имеет тип ItemCollection, а свойство CollectionView ItemCollection - внутреннее , поэтому мы не можем получить к нему прямой доступ, чтобы убедиться, что это правда , Тем не менее, мы можем просто ввести эти три значения в отладчике, чтобы убедиться в этом, все они выглядят как true

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

В качестве альтернативы, мы можем использовать отражение для сравнения в коде

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

Способ обойти это уже был опубликован F Ruffell , создайте новый ListCollectionView как ItemsSource для каждого ListBox.

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

Также обратите внимание, что после этого вышеприведенные 3 сравнения выглядят как ложные

0 голосов
/ 10 октября 2011

Из-за ссылочного типа и предоставления обоим спискам одного и того же itemSource, если вы манипулируете друг другом, также будет выполнятьсяЕсли вы хотите добиться этого, просто используйте new и переназначьте второй список, прежде чем передать его ItemsSource.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...