Suppose we want to show a dialog, when getting an exception in the task1
and from that dialog we call a method, which starts a new task2
. The problem is that the owner window freezes during task2
.
Please, take a look at the simple code (Task Parallel Library uses):
private void button1_Click(object sender, RoutedEventArgs e)
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew
(() => SomeHardMethod(1)).ContinueWith(TaskContinuation, scheduler);
}
private void TaskContinuation(Task parentTask)
{
if (parentTask.IsFaulted)
{
// If we get an exception - show a dialog that starts a new task
var dlg = new WindowDialog();
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
if (dlg.Show())
{
//Here we start a new task
Task.Factory.StartNew
(() => SomeHardMethod(2)).ContinueWith(TaskContinuation, scheduler);
}
var ex = parentTask.Exception;
}
}
private void SomeHardMethod(int mode)
{
if (mode == 1)
{
throw new ArgumentException("mode");
}
else
{ //Any long operation...
Thread.Sleep(3000);
}
}
To me, its strange that, when I firstly start the task in button1_Click
method it performs not in UI, but when I secondly start a new task it performs in UI thread, so that's why the owner window freezes.
Could anyone clarify why does this part of code actually start the task not in background?
if (dlg.Show())
{
//Here we start a new task
Task.Factory.StartNew
(() => SomeHardMethod(2)).ContinueWith(TaskContinuation, scheduler);
}
When you start a Task
using Task.Factory.StartNew()
, the current scheduler is used. What this means is that if you start a Task
this way from a Task
that executes on the UI thread, it will execute on the UI thread too. But the same won't happen if you start a Task
from the UI thread, but outside of a Task
(like in your event handler).
To make sure the Task
is executed on a background thread, you need to explicitly specify you want to use TaskScheduler.Default
.