任务在显示对话框后启动时冻结UI
本文关键字:冻结 UI 启动 显示 对话框 任务 | 更新日期: 2023-09-27 18:13:02
假设我们想要显示一个对话框,当在task1
中获得异常时,我们从该对话框中调用一个方法,该方法启动一个新的task2
。问题是task2
期间所有者窗口冻结。
请看一下简单的代码(任务并行库使用):
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);
}
}
对我来说,奇怪的是,当我第一次在button1_Click
方法中启动任务时,它不在UI中执行,但是当我第二次启动一个新任务时,它在UI线程中执行,所以这就是为什么所有者窗口冻结。
谁能澄清为什么这部分代码实际上开始任务不是在后台?
if (dlg.Show())
{
//Here we start a new task
Task.Factory.StartNew
(() => SomeHardMethod(2)).ContinueWith(TaskContinuation, scheduler);
}
当您使用Task.Factory.StartNew()
启动Task
时,将使用当前调度程序。这意味着,如果你以这种方式从在UI线程上执行的Task
启动Task
,它也将在UI线程上执行。但是,如果您从UI线程启动Task
,但在Task
之外(如在您的事件处理程序中),则不会发生相同的情况。
要确保Task
在后台线程上执行,您需要显式指定您想要使用TaskScheduler.Default
。