2

假设我们想要显示一个对话框,在task1中获取异常时,并从该对话框中调用一个方法,该方法将启动一个新的task2。问题是在task2期间,所有者窗口冻结。任务在显示对话框后启动时启动UI

请随便(Task Parallel Library用途)一起来看看简单的代码:

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); 
} 
+2

究竟是什么'WindowDialog'和它的'Show()'做了什么? – 2013-05-11 12:50:50

+0

它实际上不会改变。在我的情况下,它只是显示一个窗口,并且有一个按钮,它只是关闭它(DialogResult = true) – 2013-05-12 17:25:56

+0

它应该ShowDialog()窗口。细节很重要。 – 2013-05-12 17:28:35

回答

3

当您启动Task使用Task.Factory.StartNew(),该current scheduler使用。这意味着如果你从UI线程上执行的Task开始Task这种方式,它也会在UI线程上执行。但是,如果从UI线程启动Task,但不在Task(如在您的事件处理程序中),则不会发生同样的情况。

为确保Task在后台线程上执行,您需要明确指定要使用TaskScheduler.Default

+0

感谢您的澄清!这有助于理解现在我将尝试使用你的提示来解决问题的机制。 – 2013-05-12 17:24:03