Dot-Net

為什麼 WPF Dispatcher.Invoke 不傳播異常?

  • April 9, 2015

這是我的假設範例。我有一個非常簡單的帶有一個按鈕的 WPF 視窗。Button.Click 事件有一個類似這樣的處理程序。

Action doit = () =>
{
   Action error = () => { throw new InvalidOperationException("test"); };

   try {
       this.Dispatcher.Invoke(error, DispatcherPriority.Normal);
   } catch (Exception ex) {
       System.Diagnostics.Trace.WriteLine(ex);
       throw;
   }
};
doit.BeginInvoke(null, null);

我希望異常會被Trace.WriteLine呼叫擷取並寫下來。相反,不會擷取任何異常並且應用程序會中斷。

有人知道發生這種情況的可能解釋嗎?您建議什麼解決方法來擷取由呼叫的委託引發的異常Dispatcher.Invoke

更新 1:我throw在異常處理程式碼中添加了一個。我不想真正忽略異常。我的問題的重點是正確處理它。問題是異常處理程式碼永遠不會被執行。

請記住,這是一個假設範例。我的真實程式碼看起來不像那樣。另外,假設我無法更改要呼叫的方法中的程式碼。

更新 2:考慮這個類似的例子。我有一個 Windows 窗體視窗,而不是 WPF 視窗。它有一個按鈕,其處理程序幾乎完全相同。唯一的區別在於呼叫程式碼。它是這樣的。

this.Invoke(error);

在 Windows 窗體中,執行異常處理程式碼。為什麼有區別?

**更新:**要觀察另一個執行緒中的異常,您想使用 a Task,將其排隊到Dispatcher執行緒(使用TaskScheduler.FromCurrentSynchronizationContext),然後等待它,如下所示:

var ui = TaskScheduler.FromCurrentSynchronizationContext();
Action doit = () => 
{ 
   var error = Task.Factory.StartNew(
       () => { throw new InvalidOperationException("test"); },
       CancellationToken.None,
       TaskCreationOptions.None,
       ui); 

   try { 
       error.Wait(); 
   } catch (Exception ex) { 
       System.Diagnostics.Trace.WriteLine(ex); 
   } 
}; 
doit.BeginInvoke(null, null); 

**更新(再次):**由於您的目標是可重用組件,因此我建議您遷移到Task基於 -based 的介面或其他基於事件SynchronizationContext非同步模式,而不是將組件基於Dispatcheror ISynchronizeInvoke

Dispatcher- 基於組件僅適用於 WPF/Silverlight;ISynchronizeInvoke基於 - 的組件僅適用於 Windows 窗體。SynchronizationContext基於 - 的組件將透明地與 WPF 或 Windows 窗體一起工作,並且(需要做更多工作)ASP.NET、控制台應用程序、Windows 服務等。

基於事件的非同步模式是編寫SynchronizationContext基於組件的舊推薦方式;對於 .NET 3.5 時代的程式碼,它仍然存在。但是,如果您使用的是 .NET 4,則任務並行庫更加靈活、簡潔且功能強大。下面的TaskScheduler.FromCurrentSynchronizationContext用途SynchronizationContext,是編寫需要這種同步的可重用組件的新方法。

引用自:https://stackoverflow.com/questions/3113652