我正在使用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
答案 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包围。