2

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

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

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

我的MainWindow还包含一个Frame内容。此内容的 ViewModelCustomerViewModel已在其构造函数中注册以接收这些通知:

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我的视图上的属性来限制的,所以我认为这就是问题所在。我找到了这篇文章,它定义了一个TraceListener使用PresentationTraceSources该类的。数据绑定异常现在被捕获,但是......不是通过 MessageBus 执行的代码中抛出的异常。

我创建了一个演示此行为的解决方案,可以在此处下载。

这就是我卡住的地方。我错过了什么?我如何捕捉这些异常?

提前非常感谢。

J.P

4

1 回答 1

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 中排队时,您没有机会处理抛出的异常。另请参阅此帖子以获取更多信息。

您唯一的选择是确保您自己注册的方法的代码始终被 try-catch-block 包围。

于 2013-02-12T13:27:41.650 回答