2

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

3 回答 3

3

好吧,我不知道为什么它不起作用,但在这一点上,我假设它是 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}" />

现在它可以完美运行了。

于 2010-10-21T18:27:35.293 回答
1

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

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

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

于 2010-10-21T17:00:11.617 回答
1

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

问题是由于某种原因未正确订阅 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;
        }
    }
}
于 2020-10-23T03:48:55.903 回答