CollectionViewSource, как фильтровать данные?

Я привязываю ComboBox к Entities, но хочу, чтобы данные были отфильтрованы.

До сих пор я пробовал два способа:

  • "простой": применить фильтр непосредственно к ObjectSet через LINQ to Entities.
  • установка обработчика событий фильтрации, как описано в msdn

Меня устраивает первый подход, прежде всего потому, что запрос, сгенерированный к базе данных, содержит предложение WHERE, поэтому не все данные должны быть получены с удаленной базы данных ....

Однако подход №2 намного более гибкий, если во время выполнения я хотел бы изменить применяемую фильтрацию ... Я последовал примеру на msdn, но получаю исключение, почему?

Итак, мои вопросы:
1. Какой подход лучше
2. Почему я получаю исключение?

Вот мой код:

 private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        //Do not load your data at design time.
        if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
        {
            //Load your data here and assign the result to the CollectionViewSource.
            System.Windows.Data.CollectionViewSource myCollectionViewSource =
                (System.Windows.Data.CollectionViewSource)
                this.Resources["tSCHEDEViewSource"];

            // If I use this I get the data filtered on startup, but is it the right mode?
            //myCollectionViewSource.Source = _context.TSCHEDE.Where(s => s.KLINEA == kLinea && s.FCANC == "T").OrderBy(s => s.DSCHEDA).OrderByDescending(s => s.DSTORICO);

            // Instead If I apply my custom filtering logic
            myCollectionViewSource.Filter += new FilterEventHandler(filterSource);

            myCollectionViewSource.Source = _context.TSCHEDE; // ... Here i get an exception: 
            // 'System.Windows.Data.BindingListCollectionView' view does not support filtering. ???
        }
    }


    private void filterSource(object sender, FilterEventArgs e)
    {
        TSCHEDE scheda = e.Item as TSCHEDE;
        if (scheda != null)
        {
            if (scheda.KLINEA == 990)
            {
                e.Accepted = true;
            }
            else
            {
                e.Accepted = false;
            }
        }
    }

EDIT: я попытался реализовать свойство Filter в представлении, а не устанавливать EventHandler:

myCollectionView = (BindingListCollectionView)myCollectionViewSource.View;
myCollectionView.Filter = new Predicate<object>(Contains);

public bool Contains(object de)
    {
        TSCHEDE scheda = de as TSCHEDE;
        return (scheda.KLINEA == 990);
    }

И теперь я получаю исключение не очень полезное:

System.NotSupportedException: указанный метод не поддерживается. в System.Windows.Data.CollectionView.set_Filter (значение Predicate`1)

ИЗМЕНИТЬ

Код XAML:

<UserControl.Resources>
    <CollectionViewSource x:Key="tSCHEDEViewSource" d:DesignSource="{d:DesignInstance my:TSCHEDE, CreateList=True}"  >
    </CollectionViewSource>
    <DataTemplate x:Key="SchedaTemplate">
        <StackPanel Orientation="Horizontal" >
            <TextBlock Text="{Binding Path=KSCHEDA}" Width="60"></TextBlock>
            <TextBlock Text="{Binding Path=DArticolo}" Width="200"></TextBlock>
            <TextBlock Text=" - " Width="40"></TextBlock>
            <TextBlock Text="{Binding Path=DSTORICO}" Width="150"></TextBlock>
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>
<Grid Background="PapayaWhip" DataContext="{StaticResource tSCHEDEViewSource}" DataContextChanged="StartHere" Name="rootGrid">
    <ComboBox ItemTemplate="{StaticResource SchedaTemplate}" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" ItemsSource="{Binding}" Margin="23,129,0,0" Name="tSCHEDEComboBox1" SelectedValuePath="KSCHEDA" VerticalAlignment="Top" Width="393">
        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>
    </ComboBox>
</Grid>

Теперь я думаю, что проблема в привязке XAML, а не в коде позади ...


person spiderman    schedule 24.01.2013    source источник


Ответы (2)


Проверь это

1) Фильтрация CollectionView

Для фильтрации требуется делегат (предикат), на основе которого будет выполняться фильтрация. Предикат принимает элемент на основе возвращаемого значения true или false, он выбирает или отменяет выбор элемента.

this.Source.Filter = item => {
    ViewItem vitem = item as ViewItem;
    return vItem != null && vitem.Name.Contains("A");
};

2) Динамическая фильтрация данных

person Master Stroke    schedule 24.01.2013
comment
Я следил за вами по первой ссылке, но через некоторое время все становится слишком сложным ... Прежде всего, то, что я получаю от myCollectionViewSource.View, - это ICollectionView, и он, похоже, не поддерживает сортировку фильтрации (свойства CanSort , CanFilter ложны) В XAML у меня есть: ‹CollectionViewSource x: Key = tSCHEDEViewSource d: DesignSource = {d: DesignInstance my: TSCHEDE, CreateList = True} /› - person spiderman; 24.01.2013
comment
программисты, рожденные для сложных вещей :-) - person Master Stroke; 24.01.2013
comment
Фактически, это был ответ. - person Shaun Wilson; 23.02.2014

Последнее, что я нашел решение, также опубликовано в этом вопросе, чтобы явно указать тип Коллекции:

CollectionViewType = "ListCollectionView"

Итак, в XAML добавлен тип коллекции:

<CollectionViewSource x:Key="tSCHEDEViewSource" d:DesignSource="{d:DesignInstance my:TSCHEDE,  CreateList=True}" CollectionViewType="ListCollectionView">
    </CollectionViewSource>

И теперь в коде обработчик событий работает:

myCollectionViewSource.Filter += new FilterEventHandler(filterSource);

Сожалею только о том, что я не понял, почему для чего-то, казалось бы, такого простого, я должен принудительно принудительно использовать его в XAML ??? Мне это кажется взломом, а также очень ошибкой склонный...

person spiderman    schedule 24.01.2013
comment
Разве вы просто не ненавидите, когда кто-то голосует, не оставляя комментариев? - person Warlord 099; 25.03.2015
comment
Может они получили эту ошибку - CollectionViewType property can only be set during Initialization. - person epicTurk; 17.08.2016
comment
@ Warlord099 Это странно. Мы никогда не жалуемся на голоса за ... просто мысли. Но да, мы почти уверены, что это было сделано, потому что комментарий / пост помог человеку. - person Yatin; 03.08.2017
comment
@ Ятин Это действительно не так уж и странно. Если ответ уже правильный / полезный, возможно, добавление чего-либо еще принесет пользу. Однако, если ответ НЕ правильный / полезный, тогда всегда полезно объяснить, почему. В любом случае, теперь это принятый ответ, несмотря на то, что более двух лет назад, когда я сделал свой первоначальный комментарий, я получил несколько голосов против. - person Warlord 099; 07.08.2017
comment
Если вы получаете эту ошибку, свойство CollectionViewType можно установить только во время инициализации., Просто установите CollectionViewType в качестве первого атрибута в XAML перед любым другим атрибутом. Я знаю, что это старый ответ, но, возможно, это может кому-то помочь. - person Ader Silva; 17.05.2019