WPF - 在SimpleMVVM messagebus执行的代码中捕获异常

时间:2013-02-10 02:18:53

标签: wpf exception-handling simple-mvvm

我正在使用SimpleMVVM framework构建WPF应用程序,但我无法捕获异常。我使用SimpleMVVM的MessageBus将消息发送到另一个viewmodel。这一切都运行正常,但我注意到消息总线执行的代码中引发的异常被抑制。这是我到目前为止所得到的:

我的MainWindow包含一个在MainWindowViewModel上触发TempCommand的按钮。该命令依次调用Test方法(如下所示),该方法使用SimpleMVVM的MessageBus发送通知消息。

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

我的MainWindow还包含内容Frame。此内容的ViewModel 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,它定义了使用TraceListener类的PresentationTraceSources。现在可以捕获数据绑定异常,但是......不是通过MessageBus执行的代码中抛出的异常。

我已经创建了一个演示此行为的解决方案,可以下载here

这就是我被困住的地方。我错过了什么?我如何捕获这些例外?

提前非常感谢。

JP

1 个答案:

答案 0 :(得分: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包围。