2010-01-29 2 views
13

Я написал пользовательский элемент управления WPF с расширением поиска, назовем его MyControl. Контроль является потомком класса ItemsControl.WPF CollectionViewSource Несколько просмотров?

Так что кормить источник данных, чтобы это следующим образом:

Самим управления использует

protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue) 
{ 
    if (newValue != null) 
    { 
     ICollectionView view = CollectionViewSource.GetDefaultView(newValue); 
     view.Filter += this.FilterPredicate; 
    } 

    if (oldValue != null) 
    { 
     ICollectionView view = CollectionViewSource.GetDefaultView(oldValue); 
     view.Filter -= this.FilterPredicate; 
    } 

    base.OnItemsSourceChanged(oldValue, newValue); 
} 

для фильтрации вида коллекции источника (таким образом, отображая его во внутреннем ListBox).

Теперь предположим, что у нас есть 10 из этих MyControls, определенных в XAML с тем же DynamicSource. Проблема заключается в том, что если один из них применит фильтр к исходной коллекции, это затронет и все остальные экземпляры.

Как вы изменили бы элемент управления, чтобы избежать такого поведения?

ответ

26

В подобных ситуациях вы обычно хотели бы создать отдельный экземпляр ICollectionView для каждого различно фильтрованного использования коллекции. Не рекомендуется использовать конкретную реализацию ICollectionView, так как тип CollectionView может измениться, если ItemsSource привязан к другому типу коллекции. Использование

ICollectionView filteredView = new CollectionViewSource { Source=newValue }.View; 

будет автоматически отображать ICollectionView.

К сожалению, в этом случае вы можете обнаружить, что очень сложно применить отдельную коллекцию к ItemsPresenter вашего настраиваемого элемента управления, поскольку все это волшебство сделано для вас базовым классом ItemsControl и полагается на ItemsSource/Свойства элементов, которыми он управляет. Это происходит при использовании чего-то похожего на шаблон DefaultControl.

Если вы фактически используете отдельный элемент управления ListBox (и TemplateBinding все свойства ItemsSource, если они вам нужны) внутри вашего ControlTemplate, тогда вы должны просто добавить новый ICollectionView DP (я бы рекомендовал только чтение) на вашем элементе управления, чтобы сохранить отфильтрованную версию коллекции и связать элемент ItemsSource ListBox с этим новым свойством.

+0

ОК здорово это действительно работает .. Большое спасибо! Просто вопрос noobie - это .RegisterReadOnly(), что вы подразумеваете под словом «readonly»? –

+0

Я спрашиваю, потому что в ItemsSourceChanged я устанавливаю ItemSourceView = new CollectionViewSource {Source = newValue} .View, где ItemsSourceView является DP, поэтому я не могу просто удалить установщик. –

+2

Да. Это немного больше, чем просто изменение инициализации: private static readonly DependencyPropertyKey MyDPPropertyKey = DependencyProperty.RegisterReadOnly (...); public static readonly DependencyProperty MyDPProperty = MyDPPropertyKey.DependencyProperty; общественный объект MyDP { \t get {return (object) GetValue (MyDPProperty); } \t частный набор {SetValue (MyDPPropertyKey, value); } } –

4

Проблема заключается в том, что CollectionViewSource.GetDefaultView(object) всегда будет возвращать тот же экземпляр ICollectionView для данного источника, и это то, что будет использовать расширение ItemsControl при отображении этого источника.

Вы можете обойти это, создав новый экземпляр ICollectionView, который будет использоваться каждым элементом управления, который вы хотите иметь возможность самостоятельно фильтровать коллекцию, а затем явно привязать свойство ItemsSource каждого элемента управления к этому конкретному виду. Тип ICollectionView будет зависеть от вашего сценария, но ListCollectionView в целом подходит.

 Смежные вопросы

  • Нет связанных вопросов^_^