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