1

I have a list with 10 million items, and I want to search through the items like an auto completion on a TextBox, but when I press a key it takes forever for the collectionViewSource filter to return. How can I do the filtering/refreshing process inside a Thread or a BackgroundWorker?

UI:

<Window 
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="350" Width="525">
  <Grid>
    <TextBox TextChanged="txtSearch_OnTextChanged"/>            
    <ListBox ItemsSource="{Binding MyCollection}" >
  </Grid>
</Window>

Code Behind:

private string _filterString;
public string FilterString
{
    get => _filterString;
    set
    {
        _filterString = value;
        NotifyPropertyChanged("FilterString");
        _myCollection.Refresh();
    }
}

private ICollectionView _myCollection;
public ICollectionView MyCollection
{
    get => _myCollection;
    set 
    { 
        _myCollection = value; 
        NotifyPropertyChanged("MyCollection"); 
    }
}

MyCollection = CollectionViewSource.GetDefaultView(db.GetSampleCollection());
MyCollection.Filter = FilterResult;

public bool FilterResult(object obj)
{
    var words = obj as List<string>;
    return words.AsParallel().Any(t => t.Contains(_filterString));    
}

private async void txtSearch_OnTextChanged(object sender, TextChangedEventArgs e)
{
    FilterString = txtSearch.Text;    
}
Ayub
  • 2,345
  • 27
  • 29
  • Collectionviewsource filtering is quite a costly and hence slow process. If this is the only reason you're using collectionview then just a List or obsevablecollection might be a better idea. If you set a property and raise property change then that notification is marshalled. Meaning you probably wouldn't need to return the collection to the ui thread. Although it might well be clearer if you do so. – Andy Feb 26 '20 at 09:16
  • 1
    It can be useful for you [Why is Parallel.ForEach much faster then AsParallel().ForAll() even though MSDN suggests otherwise?](https://stackoverflow.com/questions/25907829/why-is-parallel-foreach-much-faster-then-asparallel-forall-even-though-msdn?noredirect=1&lq=1) Have you tried to remove `AsParallel()`? – Rekshino Feb 26 '20 at 09:48
  • @Rekshino Yes, I added it later, but nothing changed. – Ayub Feb 26 '20 at 13:38
  • @Andy I didn't understand what you said: "If you set a property and raise property change then that notification is marshalled." I use `CollectionViewSource`, because I need `CustomSort` – Ayub Feb 26 '20 at 13:45
  • 1
    When you raise an event you might expect that to have thread affinity. Notifypropertychanged doesn't because there's some code runs that transfers it across to the ui thread. That transfer process is called marshalling. You can do custom sorting without collectionviewsource using various approaches including linq. – Andy Feb 26 '20 at 16:00

1 Answers1

2

The only way to do this is to make a new instance of the CollectionViewSource in the background thread, filter it there, and once done, return it to the UI thread and there just replace the current DataSource of your grid with the newly created and filtered CollectionViewSource.

Nick
  • 4,787
  • 2
  • 18
  • 24
  • 1
    I'd appreciate it, if you enrich your description with a simple sample code. A simple code illustrates thousands of words. Certainly my problem, is/will be the problem of many others. – Ayub Feb 26 '20 at 08:53