2013-02-10 89 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