I am working on a WPF desktop application using the MVVM pattern.
I am trying to filter some items out of a ListView based on the text typed in a TextBox. I want the ListView items to be filtered as I change the text.
I want to know how to trigger the filter when the filter text changes.
The ListView binds to a CollectionViewSource, which binds to the ObservableCollection on my ViewModel. The TextBox for the filter text binds to a string on the ViewModel, with UpdateSourceTrigger=PropertyChanged, as it should be.
<CollectionViewSource x:Key="ProjectsCollection"
Source="{Binding Path=AllProjects}"
Filter="CollectionViewSource_Filter" />
<TextBox Text="{Binding Path=FilterText, UpdateSourceTrigger=PropertyChanged}" />
<ListView DataContext="{StaticResource ProjectsCollection}"
ItemsSource="{Binding}" />
The Filter="CollectionViewSource_Filter" links to an event handler in the code behind, which simply calls a filter method on the ViewModel.
Filtering is done when the value of FilterText changes – the setter for the FilterText property calls a FilterList method that iterates over the ObservableCollection in my ViewModel and sets a boolean FilteredOut property on each item ViewModel.
I know the FilteredOut property is updated when the filter text changes, but the List does not refresh. The CollectionViewSource filter event is only fired when I reload the UserControl by switching away from it and back again.
I’ve tried calling OnPropertyChanged("AllProjects") after updating the filter info, but it did not solve my problem.
(“AllProjects” is the ObservableCollection property on my ViewModel to which the CollectionViewSource binds.)
How can I get the CollectionViewSource to refilter itself when the value of the FilterText TextBox changes?
Many thanks
Don’t create a
CollectionViewSourcein your view. Instead, create a property of typeICollectionViewin your view model and bindListView.ItemsSourceto it.Once you’ve done this, you can put logic in the
FilterTextproperty’s setter that callsRefresh()on theICollectionViewwhenever the user changes it.You’ll find that this also simplifies the problem of sorting: you can build the sorting logic into the view model and then expose commands that the view can use.
EDIT
Here’s a pretty straightforward demo of dynamic sorting and filtering of a collection view using MVVM. This demo doesn’t implement
FilterText, but once you understand how it all works, you shouldn’t have any difficulty implementing aFilterTextproperty and a predicate that uses that property instead of the hard-coded filter that it’s using now.(Note also that the view model classes here don’t implement property-change notification. That’s just to keep the code simple: as nothing in this demo actually changes property values, it doesn’t need property-change notification.)
First a class for your items:
Now, a view model for the application. There are three things going on here: first, it creates and populates its own
ICollectionView; second, it exposes anApplicationCommand(see below) that the view will use to execute sorting and filtering commands, and finally, it implements anExecutemethod that sorts or filters the view:Sorting kind of sucks; you need to implement an
IComparer:To trigger the
Executemethod in the view model, this uses anApplicationCommandclass, which is a simple implementation ofICommandthat routes theCommandParameteron buttons in the view to the view model’sExecutemethod. I implemented it this way because I didn’t want to create a bunch ofRelayCommandproperties in the application view model, and I wanted to keep all the sorting/filtering in one method so that it was easy to see how it’s done.Finally, here’s the
MainWindowfor the application: