WPF - событие фильтра CollectionViewSource в DataTemplate не работает - PullRequest
2 голосов
/ 21 октября 2010

Я вижу странное поведение, когда 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, событие «Фильтр» работает нормально.

РЕДАКТИРОВАТЬ:

Например, следующие операции работают, как ожидается, с фильтром списка, как ожидалось.

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

Ответы [ 2 ]

3 голосов
/ 21 октября 2010

Ну, я не знаю, почему это не работает, но на данный момент, я предполагаю, что это ошибка Microsoft.Вероятно, я скоро подам отчет о подключении.

Чтобы обойти эту ошибку, я сделал следующее.Я создал подкласс 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 голос
/ 21 октября 2010

Вы используете Фильтр, как будто это свойство в CollectionViewSource, которое всегда используется.

Это не так. Это событие. Он говорит: «Когда вы фильтруете этот CollectionViewSource, будет вызываться это событие». Он будет отвечать на запросы на фильтрацию, но сам не будет запускать эти запросы.

Я не очень много знаю о CollectionViewSource, но я предполагаю, что вам придется привязать его к элементу управления фильтрацией, чтобы запустить это событие, например Grid, который разрешил фильтрацию.

...