WPF - DataTemplate中的CollectionViewSource Filter事件无法正常工作

时间:2010-10-21 16:21:44

标签: wpf datatemplate collectionviewsource

我看到一些非常奇怪的行为,其中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");
        }
    }
}

3 个答案:

答案 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;
        }
    }
}