Alfie
Alfie

Reputation: 297

How to keep the UI responsive while doing background tasks

I have implemented a refresh button, which reads the database and checks for any new entrys and adds them to an ObservableCollection. I have a refresh icon which spins dependsing on the value of IsRefreshing. Like so:

new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;
            IsRefreshing = true;

            //Reads database
            //ObservableCollection.Add(NewValues)

            IsRefreshing = false;
        }).Start();

But running this gives me the exception:

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

I am obviously going about this the wrong way, but not sure how I should how to keep the UI responsive while doing background tasks?

Upvotes: 1

Views: 1045

Answers (2)

Robert
Robert

Reputation: 2543

Basically you have to add this item to the collection but you have to do it on the Dispatcher thread like so:

Application.Current.Dispatcher.Invoke(() => ObservableCollection.Add(NewValues));

Upvotes: 1

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131774

You can't modify the UI from a background thread. All supported .NET versions allow using async/await to execute something in the background and get back to the UI thread.

ADO.NET, Entity Framework, Dapper and most ORMs support asynchronous execution. For example, ADO.NET's ExecuteReader has an equivalent ExecuteReaderAsync method. EF's ToList() has a ToListAsync(). Dapper's Query has QueryAsync

You should change your event handler to something like this :

private async void btn1_Click(object sender, RoutedEventArgs e)
{
    using(var connection = new SqlConnection(_cnString)
    {
        IsRefreshing = true;
        await connection.OpenAsync();
        var results=await connection.QueryAsync<Value>(query);
        //We're now back in the UI thread
        _theCollection.AddRange(results);
        IsRefreshing = false;
    }
}

When OpenAsync or QueryAsync are called, .NET will run the query in the background and release the current (UI) thread. When the query completes await ensures that execution will resume on the original thread, ie the UI thread.

Upvotes: 3

Related Questions