2013-02-10 35 views
2

我正在構建使用SimpleMVVM framework的WPF應用程序,並且在捕獲異常時遇到問題。我使用SimpleMVVM的MessageBus將消息發送到另一個視圖模型。這一切都正常,但我注意到由messagebus執行的代碼中引發的異常被抑制。這裏是我到目前爲止:WPF - 在由SimpleMVVM messagebus執行的代碼中捕獲異常

我的MainWindow包含一個按鈕,在MainWindowViewModel上觸發TempCommand。該命令依次調用Test方法(如下所示),該方法使用SimpleMVVM的MessageBus發送通知消息。

private void Temp() 
{ 
    SendMessage("Temp", new NotificationEventArgs()); 
} 

我的MainWindow還包含一個帶有內容的Frame。此內容的視圖模型,CustomerViewModel,已登記在其構造函數接收這些通知:

public CustomerDetailsViewModel(ICustomerServiceAgent agent) 
{ 
    RegisterToReceiveMessages("Temp", Temp); 
} 

Temp方法簡單地拋出一個異常:

private void Temp(object sender, NotificationEventArgs args) 
{ 
    throw new NotImplementedException("Somewhere, something horrible happened"); 
} 

當我調試應用程序,我清楚地看到正在調用Temp方法並引發異常。但由於某種原因,就是這樣。應用程序不受影響,我的異常陷印代碼不知道該異常。

我以兩種方式捕獲異常。第一種是通過在Dispatcher處理事件:

<Application x:Class="MyApp" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      StartupUri="MainWindow.xaml" 
      DispatcherUnhandledException="App_DispatcherUnhandledException"> 

當後臺代碼的樣子:

private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 
{ 
    Log("Exception: " + e.Exception.Message); 
    e.Handled = true; 
} 
public static void Log(string message) 
{ 
    File.AppendAllText(@"D:\Temp\log.txt", "[" + DateTime.Now.ToString("F") + "] [" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "] " + message + Environment.NewLine); 
} 

此代碼捕獲一些例外,但不是全部。我發現WPF默認禁止數據綁定例外。因爲我的ViewModel在我的視圖中通過DataContext屬性有界,所以我認爲這是問題所在。我找到了this article,它定義了使用PresentationTraceSources類的TraceListener。數據綁定異常現在被捕獲,但是...不是通過MessageBus執行的代碼中拋出的異常。

我創建了一個演示此行爲的解決方案,它可以下載here

這就是我卡住的地方。我錯過了什麼?我如何捕獲這些例外情況?

非常感謝提前。

JP

回答

1

我認爲這是在SimpleMVVM的MessageBus的實現中的錯誤或問題。

原因多個訂閱者可以訂閱令牌,當前的實現確保每個訂閱的方法即使在一個註冊的方法拋出異常時也會被調用。在這種情況下,捕獲異常並將其寫入控制檯。

,它負責調用訂閱方法,該方法是SafeNotify

private void SafeNotify(Action method, bool post) { 
    try { 
    // Fire the event on the UI thread 
    if (post){ 
     if (Dispatcher.CheckAccess()){ 
     method(); 
     } 
     else{ 
     Dispatcher.BeginInvoke(method); 
     } 
    } 
    // Fire event on a ThreadPool thread 
    else{ 
     ThreadPool.QueueUserWorkItem(o => method(), null); 
    } 
    } 
    catch (Exception ex){ 
    // If there's an exception write it to the Output window 
    Debug.WriteLine(ex.ToString()); 
    } 
} 

當方法調用ThreadPool中被排隊,你就沒有機會來處理拋出的異常。有關更多信息,另請參閱this post

您唯一的選擇是確保您自己的註冊方法的代碼總是被try-catch-block包圍。

+0

這絕對是SimpleMVVM消息總線中的一個錯誤。它應該將消息廣播給所有客戶端,但仍可能通過AggregateException冒出任何異常。 – 2013-02-18 16:06:50

+0

感謝您的回答。我想我能做的最好的事情就是儘可能多地捕捉異常,並且對MessageBus調用的函數格外小心。另外,我的Reflector是唯一一個在檢查'InternalNotify'函數時會崩潰的嗎?再次感謝。 – 2013-02-19 00:54:52