Search code examples
c#wpffiltericollectionviewcollectionview

Filter a collection multiple times using ICollectionView


I'm trying to filter an ObservableCollection that is displayed in a DataGrid. This works great the first time, but when I try to filter again, it uses the sourcecollection instead of the filtered result. Short code example:

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);
view.Filter = delegate(object item){
  User user = item as User;
  if(user != null && user.Name.ToLower().Contains(textbox.Text.ToLower())) return true;
  return false;
};

So what I want to do is filter only the items that are shown in my DataGrid, and NOT the entire collection (of course the first time that the filter is used, it will use the entire collection).


Solution

  • The real problem you should be fixing is the performance of CollectionView Filter, instead of implementing nested filters by feeding back the newly filtered list as source collection to next filter.

    The nested filter / feedback source collection method that you "want", will cause issues when user performs several attempts of typing and removing characters because then you will not be sure which source collection applies to that filter text.

    E.g. We have 100 employees and we filter it by typing "Employee Name" as "A"... This lists 50 employees with names starting with "A". Now we continue to type "H"... 10 employess from those 50 having names starting with "AH" are filtered. But now we remove "H", ideally it should use 100 employees to search new list of employees but it will use 10 employees as that is fed back to the nested filtering process.

    Imagine how complicated it will get if someone frequently types and removes random characters from the filtered text!

    So ground rule is You must filter in the entire source collection

    Once we know this now we can try to improve the filter functionality...

    1. Use LINQ and set the result to the ItemsSource of the DataGrid on each typed character. They work great for large collections (I had one such datagrid having 300 thousand rows and I used LINQ to perform fast filtering).

    2. LINQ can run on a background thread and reapply result to the ItemsSource of the datagrid.

    3. If in .Net 4.0, LINQ offers AsParallel() calls. Very effective. Uses limited number of pooled threads for filtering.

    4. LINQ also offers AsQueryable() interface for string property name based search.