2013-04-22 24 views
1

我想要使用WPF窗口而不是常規Windows.MessageBox,主要是因爲我希望它具有「詳細信息」框以顯示錯誤。這工作正常,直到我開始進入線程。從任務中的Catch語句顯示自定義彈出窗口

我想運行一個任務,該任務將獲取SQL Server數據庫中可能需要一段時間的表的列表。如果出現錯誤 - 比如嘗試連接時發生超時 - 我想顯示帶有例外細節的自定義彈出窗口。

在拳頭,它不斷崩潰。經過一些閱讀之後(對你們來說),我發現Task不在UI線程中,並且不能顯示一個窗口(原生的MessageBox看起來仍然工作)。所以,我想出了以下情況:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Task t = Task.Factory.StartNew(() => DoWork()); 
    } 

    void DoWork() 
    { 
     Thread thread = new Thread(() => 
     { 
      Window1 popup = new Window1(); 
      popup.Show(); 
      System.Windows.Threading.Dispatcher.Run(); 
     }); 

     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 
    } 
} 

這是一個臨時的應用程序我做了,所以我可以證明我在做什麼的基礎知識。在主應用程序中,我將該異常作爲參數發送到彈出窗口。

我的問題是:這是做到這一點的最好方法嗎?它似乎工作正常,但沒有100%確定這是最好的做法混合這樣的線程,並認爲我會把它放在那裏。

如果是好的解決方案,我的下一個問題是如何將彈出窗口與父窗口綁定在一起,以防止用戶在彈出窗口打開時關閉父窗口,或者在父窗口關閉時彈出關閉窗口?父母本身不會是主要的應用程序。

回答

4

我認爲最好的方法是在應用程序的主UI線程上顯示窗口。

您可以通過將Dispatcher傳遞給DoWork()來實現。但是分開執行計算和顯示錯誤的顧慮也是有意義的。所以,你可以做的是讓DoWork()拋出並處理異常,繼續Task。只有當出現錯誤時,將繼續運行,將在主UI線程的上下文中運行:

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Factory.StartNew(DoWork) 
     .ContinueWith(
      task => ErrorBox.Show(task.Exception), 
      CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, 
      TaskScheduler.FromCurrentSynchronizationContext()); 
} 

private void DoWork() 
{ 
    throw new Exception(); 
} 

(假設ErrorBox.Show()創建和顯示窗口。)

+0

美麗!這工作完美。關鍵是設置TaskScheduler。謝謝您的幫助!!我現在唯一奇怪的是,如果我在彈出窗口的.Show()之前放置一個斷點,然後點擊它鎖定程序,但沒有斷點,它工作正常。似乎是我彈出的問題,所以我必須查看它。 – Ernie 2013-04-22 21:51:14