Search code examples
c#wpfxamlmvvmcollectionviewsource

Filter CollectionViewSource by search string - bound to itemscontrol (WPF MVVM)


Is there a way I can filter the CollectionViewSource to only show games in the ItemsSource which "Title" contains the "searchString"?

In my PosterView I have this CVS:

<CollectionViewSource x:Key="GameListCVS"
                      Source="{Binding PosterView}"
                      Filter="GameSearchFilter">
    <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Title" />
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

and also this ItemsControl

<ItemsControl x:Name="gameListView"
              ItemsSource="{Binding Source={StaticResource GameListCVS}}">

My MainWindow.xaml contains the search box which can successfully pass the searchString (string containing what is in the search box) to PosterView.

PosterView binding is actually (confusingly, I know), an ObservableCollection

public ObservableCollection<GameList> PosterView { get; set; }

And here is how games are added to the ObservableCollection

games.Add(new GameList
{
    Title = columns[0],
    Genre = columns[1],
    Path = columns[2],
    Link = columns[3],
    Icon = columns[4],
    Poster = columns[5],
    Banner = columns[6],
    Guid = columns[7]
});

Solution

  • If you are creating the CollectionViewSource in the view, you should filter it there as well:

    private void GameSearchFilter(object sender, FilterEventArgs e)
    {
        GameList game = e.Item as GameList;
        e.Accepted = game != null && game.Title?.Contains(txtSearchString.Text);
    }
    

    The other option would be to bind to an ICollectionView and filter this one in the view model:

    _view = CollectionViewSource.GetDefaultView(sourceCollection);
    _view.Filter = (obj) => 
    {
        GameList game = obj as GameList;
        return game != null && game.Title?.Contains(_searchString);
    };
    ...
    public string SearchString
    {
        ...
        set { _searchString = value; _view.Refresh(); }
    }
    

    Or sort the source collection itself directly.