我看到一些非常奇怪的行为,其中WPF没有做我期望它做的事情。我已经设法将问题归结为下面的代码:
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<TabControl x:Name="tabControl">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type List}">
<UserControl>
<UserControl.Resources>
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource filteredValues}}" />
</UserControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
代码隐藏:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.tabControl.ItemsSource = new List<List<string>>()
{
new List<string>() { "a", "b", "c"},
};
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
string item = (string)e.Item;
e.Accepted = item.StartsWith("b");
}
}
}
我希望此代码会生成一个TabControl
,其中包含一个ListBox
个标签,其中一个项目显示为“b”。但是,相反,我得到了ListBox
所有3个字符串。在CollectionViewSource_Filter
内设置断点表明过滤器甚至不会运行。
这里发生了什么?为什么滤波器不工作?
我想也许这与CollectionViewSource
中的DataTemplate
资源有关。 ListBox
上的事件正常发生。如果UserControl
不属于DataTemplate
,则过滤器事件可以正常工作。
编辑:
例如,以下按预期工作,并按预期过滤List。
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<UserControl>
<UserControl.Resources>
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource filteredValues}}" />
</UserControl>
</Window>
代码背后:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new List<string>() { "a", "b", "c" };
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
string item = (string)e.Item;
e.Accepted = item.StartsWith("b");
}
}
}
答案 0 :(得分:2)
好吧,我不知道为什么它不起作用,但在这一点上,我认为这是一个微软的错误。我很快就会提交一份Connect报告。
要解决这个问题,我做了以下工作。我创建了CollectionViewSource
的子类,如下所示:
using System.Windows.Data;
namespace WpfApplication3
{
internal class CustomFilteredCollectionViewSource : CollectionViewSource
{
public CustomFilteredCollectionViewSource()
: base()
{
this.Filter += CustomFilter;
}
private void CustomFilter(object sender, FilterEventArgs args)
{
string item = (string)args.Item;
args.Accepted = item.StartsWith("b");
}
}
}
然后我替换了
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
与
<local:CustomFilteredCollectionViewSource x:Key="filteredValues" Source="{Binding}" />
现在效果很好。
答案 1 :(得分:1)
您正在使用Filter,就好像它是CollectionViewSource上的一个属性,它总是被使用。
不是。这是一个事件。它说,“当您过滤此CollectionViewSource时,将调用此事件。”它将响应过滤请求,但不会自动触发这些请求。
我不太了解CollectionViewSource,但我认为你必须将它绑定到过滤控件才能触发此事件,就像允许过滤的Grid一样。
答案 2 :(得分:0)
我今天也遇到了同样的问题,发现了一个更简单的解决方法。
问题是由于某种原因未正确订阅Filter事件。您可以通过在包含CollectionViewSource作为资源的控件的Loaded事件中订阅Filter来解决此问题。
将其应用于您遇到的问题中的示例
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<TabControl x:Name="tabControl">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type List}">
<UserControl Loaded="UserControl_OnLoaded">
<UserControl.Resources>
<CollectionViewSource x:Key="filteredValues" Source="{Binding}"/>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource filteredValues}}" />
</UserControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
后面的代码:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.tabControl.ItemsSource = new List<List<string>>()
{
new List<string>() { "a", "b", "c"},
};
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
string item = (string)e.Item;
e.Accepted = item.StartsWith("b");
}
private void UserControl_OnLoaded(object sender, RoutedEventArgs e)
{
var control = (UserControl) sender;
var cvs = (CollectionViewSource) control.Resources["filteredValues"];
cvs.Filter += CollectionViewSource_Filter;
}
}
}