0
\$\begingroup\$

I have around 350 People loading into a CollectionView and am already noticing some lag when filtering on their Name. This concerns me as we could easily reach> 1000 People quickly and I need filtering to be as quick as possible.

I'm trying to avoid calling Refresh() as I know this is expensive but I am not quite sure how to do this here. Here is my code:

C#

public PeopleViewModel()
{
 using (var context = new DashboardContext())
 {
 People = new ObservableCollection<Person>(context.People.ToList());
 SearchPeople = new ObservableCollection<SearchPerson>(
 People.Select(c => new SearchPerson
 {
 Id = c.Id,
 FullName = c.FullName.ToLower(),
 DisplayName = c.FullName
 }).ToList().OrderByDescending(x => x.Id));
 }
 SearchPeopleView = CollectionViewSource.GetDefaultView(SearchPeople) as CollectionView;
 if (SearchPeopleView != null) SearchPeopleView.Filter = ViewFilter;
}

C# Filter

private void FilterPeople()
{
 SearchPeopleView.Refresh();
}
private bool ViewFilter(object obj)
{
 var user = obj as SearchPerson;
 return user != null && user.FullName.Contains(_searchString);
}

XAML

<DataGrid Grid.Row="1" Margin="5"
 SelectedItem="{Binding SelectedSearchPerson}"
 ItemsSource="{Binding SearchPeopleView}"
 Style="{StaticResource HomeDataGrid}">
 <DataGrid.Columns>
 <DataGridTextColumn Binding="{Binding DisplayName}" Width="*"/>
 </DataGrid.Columns>
</DataGrid>

I use a DataGrid here as I couldn't get the styling I was looking for in a ListBox. I also created a minimal version of a Person, SearchPerson so I can search on fewer properties.

Reading around there are solutions but many are < 5 years old. I'm also aware that Contains() can be slow so I suppose I should be looking at a different approach to the Filter itself.

I'd appreciate any help and advice, thanks!

asked Oct 31, 2017 at 9:24
\$\endgroup\$
4
  • \$\begingroup\$ 1000 items to filter is like nothing and if you already experience problems with just 350 names then there is something else wrong with your code. It's not the filter function. Use a profiler to identify it or show us more. \$\endgroup\$ Commented Oct 31, 2017 at 9:30
  • \$\begingroup\$ But maybe you are calling this SearchPeopleView.Refresh(); too often and pull data from the database on each search? \$\endgroup\$ Commented Oct 31, 2017 at 9:31
  • \$\begingroup\$ You're only loading the People during construction? (So you have an in memory list of people that you're filtering?) Quick test I just knocked up with static data was still very responsive with 10 times that number of entities in it... \$\endgroup\$ Commented Oct 31, 2017 at 15:52
  • \$\begingroup\$ ex: pastebin.com/WAeJCSJe \$\endgroup\$ Commented Oct 31, 2017 at 15:58

1 Answer 1

1
\$\begingroup\$

Take a look at ReactiveExtensions (or specifically ReactiveUI). Then use something like in your VM constructor

this.WhenAnyValue(x => x.SearchString).Throttle(TimeSpan.FromMiliseconds(50).Subscribe(_ => Fitler.Refresh())

This will wait a little between each keystroke before starting the filter.

On the other hand, checkout DerivedCollection - it can move the filtering out of the UI thread, only pushing additions and removes of single items (or calling the full reset or ReactiveList if changes are big, you can set the threshold) to UI.

Still, your solution should be fast enough. Remember that it vastly depends on your DataTemplate for your filtered items - if it is complicated, most cost will be in displaying, not in filtering - especialy that it has to be done on UI thread.

answered Oct 31, 2017 at 11:21
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.