Reputation: 297
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
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
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