C#, MVVM, Tasks and the UI Thread
c#, multithreading, mvvm, task, wpf
Solution
There could be any number of reasons why the continuation is running on the UI thread. The MVVM framework could be helping, or something else is making it run on the UI thread, or you're just getting lucky.
To ensure the continuation runs on the UI thread you can capture the UI `TaskScheduler` right before like so.
var uiScheduler = TaskScheduler.FromCurrentSyncronizationContext();
Task.Factory.StartNew(() =>
UiDataProvider.RefreshForwardContractReport(fcrIdField.Value),
TaskCreationOptions.LongRunning
) // Ensures the task runs in a new thread
.ContinueWith(task => {
if (task.Result.OperationSuccess)
{
RefreshReport(task.Result.OperationResult);
}
}, uiScheduler); // Runs the continuation on the UI thread.
This assumes that the outer method is run from the UI to begin with. Otherwise you could capture the UI scheduler at a top level and access it globally in your app.
If you can use async/await then the code becomes much easier.
var result = await Task.Factory.StartNew(
() => UiDataProvider.RefreshForwardContractReport(fcrIdField.Value),
TaskCreationOptions.LongRunning
);
if (result.OperationSuccess)
{
RefreshReport(result.OperationResult);
}
Problem
We have an application built according to the MVVM pattern. At various times we kick off tasks to go to a database to retrieve data, we then populate an ObservableCollection to which a WPF control is bound with that data. We are a little confused, when we populate the ObservableCollection we are doing so on the task thread, not the UI thread, yet the UI is still updated/behaving correctly. We were expecting an error and to have to change the code to populate the collection on the UI thread. Is this a dangerous scenario and should we populate on the UI thread anyway? Code to get data: ``` Task.Factory.StartNew(() => UiDataProvider.RefreshForwardContractReport(fcrIdField.Value) ) .ContinueWith(task => { if (task.Result.OperationSuccess) { // This updates the ObseravableCollection, should it be run on UI thread?? RefreshReport(task.Result.OperationResult); } }); ```