2016-07-23 1 views
1

Необходимые условия: .NET 4.5.1Multiple ItemsControl на одной коллекции применяется фильтр ко всем представлениям сразу

У меня есть 3 элементов управления TreeView, отображающие дерево фильтруется варианты одного экземпляра коллекции. Когда я пытаюсь применить фильтр в коллекции Items одного из элементов управления, этот фильтр распространяется на другие элементы управления автоматически, что мешает мне использовать разные фильтры для разных элементов управления. Есть ли способ достичь такого же результата без необходимости одновременного хранения экземпляров деревьев?

Ниже приведен пример, который показывает проблему. Первые два ListViews привязаны к одному экземпляру коллекции напрямую. Третий связан с этим экземпляром через CompositeCollection. И четвертый связан с независимой коллекцией. Когда я нажимаю кнопку «Установить фильтр», свойство ItemsControl.Items.Filter, если в первом списке ListView установлен метод IsAllowedItem окна WTest. После этого второго свойства ListView.Items.Filter каким-то образом указывает на тот же метод, в то время как третий и четвертый ListView возвращает null. Другим эффектом является то, что хотя третий ListView отображает нулевой фильтр, его коллекция по-прежнему фильтруется, как вы можете видеть, запускаете ли вы пример. Этот очень странный эффект возникает из-за поведения класса ItemCollection, который, основываясь на свойстве ItemsSource элемента owner, приобретает базовый CollectionView из некоторого хранилища в аппликационном пространстве с помощью метода CollectionViewSource.GetDefaultCollectionView. Я не знаю причины этой реализации, но подозреваю, что это производительность.

Test окно WTest.xaml:

<Window x:Class="Local.WTest" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:s="clr-namespace:System;assembly=mscorlib" 
     xmlns:c="clr-namespace:System.Collections;assembly=mscorlib" 
     xmlns:local="clr-namespace:Local" 
     Name="_WTest" Title="WTest" Height="300" Width="600"> 
    <Window.Resources> 
     <c:ArrayList x:Key="MyArray"> 
      <s:String>Letter A</s:String> 
      <s:String>Letter B</s:String> 
      <s:String>Letter C</s:String> 
     </c:ArrayList> 
     <CompositeCollection x:Key="MyCollection" > 
      <CollectionContainer Collection="{StaticResource ResourceKey=MyArray}"/> 
     </CompositeCollection> 
     <c:ArrayList x:Key="AnotherArray"> 
      <s:String>Letter A</s:String> 
      <s:String>Letter B</s:String> 
      <s:String>Letter C</s:String> 
     </c:ArrayList> 
    </Window.Resources> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <TextBlock Grid.Row="0" Grid.Column="0" Name="FilterLabel1"/> 
     <TextBlock Grid.Row="0" Grid.Column="1" Name="FilterLabel2"/> 
     <TextBlock Grid.Row="0" Grid.Column="2" Name="FilterLabel3"/> 
     <TextBlock Grid.Row="0" Grid.Column="3" Name="FilterLabel4"/> 
     <ListView Grid.Row="1" Grid.Column="0" Name="View1" ItemsSource="{StaticResource ResourceKey=MyArray}"/> 
     <ListView Grid.Row="1" Grid.Column="1" Name="View2" ItemsSource="{StaticResource ResourceKey=MyArray}"/> 
     <ListView Grid.Row="1" Grid.Column="2" Name="View3" ItemsSource="{StaticResource ResourceKey=MyCollection}"/> 
     <ListView Grid.Row="1" Grid.Column="3" Name="View4" ItemsSource="{StaticResource ResourceKey=AnotherArray}"/> 
     <Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Content="Set Filter" Click="OnSetFilterButtonClick"/> 
    </Grid> 
</Window> 

код за WTest.xaml.cs

namespace Local { 
    using System.Windows; 

    public partial class WTest : Window { 
     public WTest() { 
      InitializeComponent(); 
      UpdateFilterLabels(); 
     } 

     private bool IsAllowedItem(object item) { 
      return "Letter A" == (string)item; 
     } 

     private void OnSetFilterButtonClick(object sender, RoutedEventArgs e) { 
      View1.Items.Filter = IsAllowedItem; 
      UpdateFilterLabels(); 
     } 

     private void UpdateFilterLabels() { 
      FilterLabel1.Text = (null == View1.Items.Filter) ? "No Filter" : View1.Items.Filter.Method.Name; 
      FilterLabel2.Text = (null == View2.Items.Filter) ? "No Filter" : View2.Items.Filter.Method.Name; 
      FilterLabel3.Text = (null == View3.Items.Filter) ? "No Filter" : View3.Items.Filter.Method.Name; 
      FilterLabel4.Text = (null == View4.Items.Filter) ? "No Filter" : View4.Items.Filter.Method.Name; 
     } 
    } 
} 

И результат после того, как "Установить фильтр" кнопка нажата: Example: result of clicking "Set Filter" button

ответ

0
  1. CollectionViewSource как Resource.

    <CollectionViewSource x:Key="CVSKey" Source="{DynamicResource MyArray}"/>.

  2. Используйте этот CollectionViewSource как ваш ItemsSource. Заменить View1 как:

    <!--<ListView Grid.Row="1" Grid.Column="0" Name="View1" ItemsSource="{DynamicResource ResourceKey=MyArray}"/>--> 
    <ListView Grid.Row="1" Grid.Column="0" Name="View1" ItemsSource="{Binding Source={StaticResource ResourceKey=CVSKey}}"/> 
    

Thats это, теперь все будет работать, как вы хотите.

Кроме того, теперь вы можете применить фильтр к этому CollectionViewSource вместо View1:

((CollectionViewSource)this.Resources["CVSKey"]).Filter += List_Filter; 

void List_Filter(object sender, FilterEventArgs e) 
    { 
     e.Accepted = (e.Item.ToString() == "Letter A") ? true : false; 
    } 

Создать отдельную CollectionViewSource для отдельного ListBoxes создавать отдельные виды из одной базовой коллекции.

Поиск google для CollectionViewSource.

+0

спасибо, проксирование с помощью CollectionViewSource. –

0

Изменение OnSetFilterButtonClick Метод, приведенный ниже

private void OnSetFilterButtonClick(object sender, RoutedEventArgs e) 
     { 
      //Create a new listview by the ItemsSource,Apply Filter to the new listview 
      ListCollectionView listView = new ListCollectionView(View1.ItemsSource as IList); 
      listView.Filter = IsAllowedItem; 
      View1.ItemsSource = listView; 
      UpdateFilterLabels(); 
     } 
+0

В одной коллекции можно создавать больше коллекций, один список привязывается к одному представлению коллекции. – zhaojingbo

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