I have a ListView that I’m filling with an ObservableCollection
I’m filtering the list from text entered in a TextBox
Here’s a section of the code I’m using:
private void Filter_TextChanged(object sender, TextChangedEventArgs e)
{
view = CollectionViewSource.GetDefaultView(Elementos_Lista.ItemsSource);
view.Filter = null;
view.Filter = new Predicate<object>(FilterList);
}
This works okay if I want to filter a list by just one criteria, but whenever I want to mix more than 1 textbox to do the filtering it always filters based on the ItemsSource, and not the current result set, meaning that there’s no accumulation of criteria.
Here’s my FilterList method.
ItemDetail item = obj as ItemDetail;
if (item == null) return false;
string textFilter = txtFilter.Text;
if (textFilter.Trim().Length == 0) return true; //this returns the unfiltered results.
if ((item.problema.ToLower().Contains(textFilter.ToLower()))) return true;
return false;
Is there a way to filter the ObservableCollection (view) by multiple criteria, that aren’t always provided at the same time?.
I have tried to change the FilterList method to evaluate various textboxes, but I would have to make an IF statement to check all the possibilities of matching the criteria.
(filter1=value , filter2=value) OR
(filter1=value , filter2=empty) OR
(filter1=empty , filter2=value)
And since I’m planning to filter by at least 5 different controls, that wouldn’t be fun at all.
Example:
List:
Maria, Age:26
Jesus, Age:15
Angela, Age:15
First Filter
Filters:
Name: //Empty
Age: 15
Result:
Jesus, Age:15
Angela, Age:15
Second Filter:
Filters:
Name: Jesus
Age: 15
Result:
Jesus, Age:15
What I’m trying to do is to apply filters to the already filtered collection, and not the original one, and this approach overwrites the applied filter with the next one.
OK, let’s see, I had something similar lying around here…
Contracts are optional of course (CodeContracts)
And then the base implementation, you’re using only strings for comparison as far as I can tell, so here’s string-only version:
Now some meaningful implementation, let’s say this is your class, for simplicity:
The filter implementation is – at the same time – the view model behind the view containing all your ‘filtering’ controls, so you bind the text box values to the properties accordingly.
Then you have a
PersonFilterobject instance in your view model.Then you just have to use the
Filterevent on theCollectionViewto some method in the view model, e.g.:Filter names have to be the same as the property names on the filtered object. 🙂
And of course you’ll have to call the
CollectionView.Refresh();somewhere, you can move it to the filter (e.g. when the property changes, you can callCollectionView.Refresh()to see the changes immediately), you can call it in the event handler, however you want.It’s quite straightforward, although the performance could be better. Unless you’re filtering a metric ton of data with a few dozen filters, you shouldn’t have too many problems with adjusting and using the snippets. 🙂