Nullqwerty
Nullqwerty

Reputation: 1168

Multi-threading WPF on the UI

In my C# WPF application I have a DataGrid and right above it there is a TextBox for the user to search and filter the grid as they type. If the user types fast though, no text will appear until 2 seconds after they type because the UI thread is too busy updating the grid.

Since most of the delay is all on the UI side (i.e. filtering the datasource is nearly instant, but rebinding and re-rendering the grid is slow), multi-threading has not been helpful. I then tried setting the dispatcher of just the grid to be at a lower level while the grid gets updated, but this didn't solve the issue either. Here's some code... Any suggestions on how to solve this type of problem?

string strSearchQuery = txtFindCompany.Text.Trim();

this.dgCompanies.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(delegate
    {
        //filter data source, then
        dgCompanies.ItemsSource = oFilteredCompanies;
    }));

Upvotes: 4

Views: 1216

Answers (2)

Barracoder
Barracoder

Reputation: 3764

Using a ListCollectionView as your ItemsSource for the grid and updating the Filter works much faster than re-assigning the ItemsSource.

The example below filters 100000 rows with no apparent lag by simply refreshing the View in the setter for the search term text property.

ViewModel

class ViewModel
    {
        private List<string> _collection = new List<string>(); 
        private string _searchTerm;

        public ListCollectionView ValuesView { get; set; }

        public string SearchTerm
        {
            get
            {
                return _searchTerm;
            }
            set
            {
                _searchTerm = value;
                ValuesView.Refresh();
            }
        }

        public ViewModel()
        {
            _collection.AddRange(Enumerable.Range(0, 100000).Select(p => Guid.NewGuid().ToString()));

            ValuesView = new ListCollectionView(_collection);
            ValuesView.Filter = o =>
                {
                    var listValue = (string)o;
                    return string.IsNullOrEmpty(_searchTerm) || listValue.Contains(_searchTerm);
                };
        }
    }

View

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />

Upvotes: 5

jimSampica
jimSampica

Reputation: 12420

If you are targeting .net 4.5, an option is to set the Delay property on your TextBox which will prevent setting the source value until a certain time threshold is met (until the user stops typing).

<TextBox Text="{Binding SearchText, Delay=1000}"/>

This waits for 1 second after there is no user input to set the source value.

Another option is to have a button trigger your filter/search instead of when the textbox changes.

Upvotes: 3

Related Questions