单个集合上的多个ItemsControl一次将过滤器应用于所有视图 [英] Multiple ItemsControl on single collection applies filter to all views at once

查看:70
本文介绍了单个集合上的多个ItemsControl一次将过滤器应用于所有视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

先决条件:.NET 4.5.1

Prerequisites: .NET 4.5.1

我有三个 TreeView 控件,它们显示单个集合实例的三个过滤后的变体.当我尝试在其中一个控件的 Items 集合上应用过滤器时,该过滤器会自动传播到其他控件,这使我无法在不同的控件上使用不同的过滤器.

I have three TreeView controls that display three filtered variants of single collection instance. When I try to apply a filter on Items collection of one of controls this filter propagates to other controls automatically which prevents me to use different filters on different controls.

是否有办法获得相同的结果而不必一次维护三个collections实例?

Is there any way to achieve the same result without having to maintain three instances of collections at once?

下面是显示问题的示例.前两个ListView直接绑定到同一集合实例.第三个通过 CompositeCollection 绑定到该实例.第四个是独立收藏.当我将第一个 ListView 设置为WTest窗口的 IsAllowedItem 方法时,按下设置筛选器"按钮的 ItemsControl.Items.Filter 属性.在第二个 istView.Items.Filter 属性之后,它以某种方式指向相同的方法,而第三个和第四个ListView返回null.另一个效果是,尽管第三个 ListView 显示了null过滤器,但您仍然可以对它的集合进行过滤,如运行示例所示.这种非常奇怪的效果来自ItemCollection类的行为,该行为基于所有者元素的 ItemsSource 属性,通过 CollectionViewSource.GetDefaultCollectionView从某个应用程序范围的存储中获取底层的 CollectionView .方法.我不知道执行此操作的原因,但怀疑它的性能.

An example that shows the problem follows below. First two ListViews are bound to the same collection instance directly. Third one is bound to that instance through CompositeCollection. And the fourth is bound to independent collection. When I press "Set Filter" button ItemsControl.Items.Filter property if first ListView is set to IsAllowedItem method of WTest window. After this second istView.Items.Filter property somehow points to the same method while third and fourth ListView returns null. Another effect is that though third ListView shows null filter its collection is still filtered as you can see if you run the example. This very strange effect arises from the behavior of ItemCollection class that when based on ItemsSource property of owner element acquires underlying CollectionView from some application-wide storage via CollectionViewSource.GetDefaultCollectionView method. I don't know the reason of this implementation but suspect suspect that it's performance.

测试窗口WTest.xaml:

Test window 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后面的代码

Code behind 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;
        }
    }
}

单击设置过滤器"按钮后的结果:示例:单击设置过滤器"按钮的结果

And result after "Set Filter" button is clicked: Example: result of clicking "Set Filter" button

推荐答案

  1. CollectionViewSource 创建为 Resource .

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

  • 使用此 CollectionViewSource 作为您的 ItemsSource .将您的View1替换为:

  • Use this CollectionViewSource as your ItemsSource . Replace your View1 as :

    <!--<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 it, now everything will work as you want it to.

    此外,现在您可以将过滤应用于此 CollectionViewSource 而不是View1:

    Additionally, now you can apply filtering to this CollectionViewSource instead of View1 :

    ((CollectionViewSource)this.Resources["CVSKey"]).Filter += List_Filter;
    
    void List_Filter(object sender, FilterEventArgs e)
    {
        e.Accepted = (e.Item.ToString() == "Letter A") ? true : false;
    }
    

    为单独的 ListBoxes 创建单独的 CollectionViewSource ,以从同一基础集合创建单独的视图.

    Create separate CollectionViewSource for separate ListBoxes to create separate views from same underlying collection.

    在Google中搜索 CollectionViewSource .

    Search google for CollectionViewSource.

    这篇关于单个集合上的多个ItemsControl一次将过滤器应用于所有视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆