【问题标题】:WPF - CollectionViewSource Filter event in a DataTemplate not workingWPF - DataTemplate 中的 CollectionViewSource 过滤器事件不起作用
【发布时间】:2010-10-21 16:21:43
【问题描述】:

我看到一些非常奇怪的行为,其中 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”。但是,相反,我得到了一个带有所有 3 个字符串的 ListBox。在CollectionViewSource_Filter 中设置断点表明过滤器甚至不会运行。

这里发生了什么?为什么过滤器不起作用?

我在想这可能与CollectionViewSourceDataTemplate 中的资源有关。 ListBox 上的事件正确触发。如果UserControl 不是DataTemplate 的一部分,则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">

    <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");
        }
    }
}

【问题讨论】:

    标签: wpf datatemplate collectionviewsource


    【解决方案1】:

    好吧,我不知道为什么它不起作用,但在这一点上,我假设这是 Microsoft 的错误。我可能很快会提交 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}" />
    

    现在可以完美运行了。

    【讨论】:

    • 这个变通方法仍然是必要的。 WPF 4.0 到今天还没有修复。
    【解决方案2】:

    您正在使用过滤器,就好像它是 CollectionViewSource 上的一个属性,它总是被使用。

    不是。这是一个事件。它说:“当您过滤此 CollectionViewSource 时,将调用此事件。”它会响应过滤请求,但不会自己触发这些请求。

    我不太了解 CollectionViewSource,但我认为您必须将其绑定到过滤控件才能触发此事件,例如允许过滤的 Grid。

    【讨论】:

    • 好像不是这样。我认为我没有很好地解释我在最后一行中的意思。但是,如果您只是将上述 XAML 中的 UserControl 作为 Window 的直接子级,则按预期调用 Filter 事件,并按预期过滤列表。稍后我将编辑问题以使其更清楚。
    • MSDN 文章及其链接的示例程序似乎与我使用的方式一致:msdn.microsoft.com/en-us/library/…
    • 看起来你设法解决了它,无论如何 - 感谢您使问题更清晰,并发布您的解决方案。现在它更有意义了。
    【解决方案3】:

    我今天遇到了同样的问题,并找到了一个更简单的解决方法。

    问题是由于某种原因未正确订阅 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;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      • 1970-01-01
      • 2015-10-02
      • 2012-06-08
      • 2013-01-05
      相关资源
      最近更新 更多