单个集合上的多个ItemsControl一次将过滤器应用于所有视图 [英] Multiple ItemsControl on single collection applies filter to all views at once
问题描述
先决条件:.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
推荐答案
-
将
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屋!