【发布时间】:2020-06-04 20:15:39
【问题描述】:
先决条件:.NET 4.5.1
我有三个TreeView 控件,它们显示单个集合实例的三个过滤变体。当我尝试对其中一个控件的 Items 集合应用过滤器时,此过滤器会自动传播到其他控件,这会阻止我在不同的控件上使用不同的过滤器。
有没有什么方法可以实现相同的结果而不必同时维护三个集合实例?
下面是一个显示问题的示例。前两个 ListView 直接绑定到同一个集合实例。第三个通过CompositeCollection 绑定到该实例。第四种必然是独立收藏。当我按下“设置过滤器”按钮 ItemsControl.Items.Filter 属性时,如果第一个 ListView 设置为 WTest 窗口的 IsAllowedItem 方法。在这第二个istView.Items.Filter 属性以某种方式指向相同的方法之后,而第三个和第四个 ListView 返回 null。另一个效果是,尽管第三个 ListView 显示空过滤器,但它的集合仍然被过滤,如果您运行该示例,您可以看到。这种非常奇怪的效果源于 ItemCollection 类的行为,即当基于所有者元素的ItemsSource 属性通过CollectionViewSource.GetDefaultCollectionView 方法从某些应用程序范围的存储中获取底层CollectionView 时。我不知道这个实现的原因,但怀疑它的性能。
测试窗口 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
【问题讨论】: