当我在事件处理程序中抛出异常时,不会调用异常处理程序吗?
从以下开始的精简示例的示例代码:
的App.xaml
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException" >
<Application.Resources/>
</Application>
App.xaml.cs
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
public partial class App : Application
{
//This method is called when ButtonA is clicked, but not when ButtonB is
//clicked (and a (random) file is selected ofcourse).
void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "An exception occurred", MessageBoxButton.OK, MessageBoxImage.Error);
e.Handled = true;
}
}
}
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button A" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonA_Click"/>
<Button Content="Button B" HorizontalAlignment="Left" Margin="90,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonB_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;
using System;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonA_Click(object sender, RoutedEventArgs e)
{
throw new Exception("Works!");
}
private void ButtonB_Click(object sender, RoutedEventArgs e)
{
var ofd = new OpenFileDialog();
ofd.FileOk += (s, ce) => {
throw new Exception("Does not work!?!?");
};
ofd.ShowDialog();
}
}
}
我已经看了this question和this question,但强制32位或64位甚至“任何CPU”都不起作用。此外,在设置任何these four(!)处理程序时,如果在事件中抛出异常,则不会调用它们。 this article也无济于事。
我正在运行VS2012(在Win8,x64上),该项目正在使用.Net Framework 4.5)。我错过了什么?我疯了吗?
为了清楚起见:我希望显示一个消息框(当我点击ButtonA
时它会显示),或者实际上,正在调用App_DispatcherUnhandledException
方法。但是当我点击ButtonB
时,不调用该方法(并且因此消息框未显示)。 ButtonA
和ButtonB
之间的唯一区别是“A
”中的异常不在事件处理程序中,而“B
”中的异常是。并且,当然,我确实在OpenFileDialog
中选择了一个文件,然后单击“打开”以选择它。调试器启动并指出“不工作!?!?”异常被抛出,然后我继续执行并且没有显示消息框。
另外:我对WPF很新,可能是问题
的一部分修改1
作为参考,这里有两个zipfiles,展示了确切的问题:
在我的计算机上,对于上述两个项目,ButtonA会显示一个消息框,ButtonB(选择文件后)则不会。永远。即使打开或未打开“调试非托管代码”,也不会。
修改2
所以,我在另一台机器上运行了相同的代码并发现了这一点:在另一台机器上,调试器显示了这个:
请注意Exception crossed a native/managed boundary
标题。当我尝试恢复执行(继续)时,异常会不断弹出。当调试器启动时,我的机器显示:
......然后,当我恢复执行时,异常会在某种黑洞中消失;主要形式再次显示,没有任何反应。
这应该与此设置有关:
但是,打开/关闭此选项无效,即使重新启动VS2012和deleting temp files(以及项目中的bin / obj目录),restoring defaults etc也是如此。
所以......我现在知道异常,实际上与托管和非托管之间的跨界有关。现在我只需要弄清楚如何解决这个问题,以便我可以在FileOk
事件中抛出异常(这样,最终,我的组件也会在那里抛出)。
答案 0 :(得分:2)
好的,所以我解决了我的问题。
谷歌搜索,浏览SO等我最终结束了here和here。现在我很清楚如何在另一个调度程序上处理FileOk事件,因此解决方案很简单:
private void ButtonB_Click(object sender, RoutedEventArgs e)
{
var ofd = new OpenFileDialog();
ofd.FileOk += (s, ce) => {
this.Dispatcher.BeginInvoke((Action)(() =>
{
//We can throw:
throw new Exception("Yay! This exception is now caught by the UnhandledException handler!");
//or, alternatively, our component can do work that possibly throws:
Component.DoFoo();
}));
};
ofd.ShowDialog();
}
这可以确保将异常传递给正确的调度程序并在那里处理。然后正确调用App_DispatcherUnhandledException
方法,我们可以从那里获取它。
答案 1 :(得分:-1)
如果你像这样连线,你会发现它正在处理中 仍然不确定为什么它会逃避App_DispatcherUnhandledException
using System.ComponentModel;
//using Microsoft.Win32;
namespace UncaughtExceptionHandler
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
//AppDomain currentDomain = AppDomain.CurrentDomain;
//currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
InitializeComponent();
}
private void ButtonA_Click(object sender, RoutedEventArgs e)
{
throw new Exception("WTFA!?!?");
}
private void ButtonB_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
ofd.FileOk += MyCanelEventHandler;
//ofd.FileOk += (s, ce) =>
//{
// //MessageBox.Show("Throwikng Exception WTF2!?!?");
// throw new Exception("WTF2!?!?");
//};
ofd.ShowDialog();
}
static void MyCanelEventHandler(Object sender, CancelEventArgs e)
{
MessageBox.Show("MyCanelEventHandler");
throw new Exception("WTFCEH!?!?");
}
}
}
调试101获得一个调用堆栈 我在10分钟内得到了一个电话堆栈。
OP做出了三个无效的假设,即使经过长时间的讨论也无法理解
- 被吞下的例外 它没有被吞没,只是越过他未被捕获的异常处理程序 我的代码证明了,但OP没有遵循
- 解决方案没有无人代码
错误的OpenFileDialog是非托管代码- 从托管代码中抛出异常 又错了 异常是从非托管代码的回调中抛出的
醇>
回调中的第一行
Degbug 101获得一个调用堆栈
UncaughtExceptionHandler.exe!UncaughtExceptionHandler.MainWindow.MyCanelEventHandler(object sender,System.ComponentModel.CancelEventArgs e)第55行C# comdlg32.dll!CFileOpenSave :: _ NotifyFileOkChangeCallback()+ 0x18 bytes comctl32.dll!_DPA_EnumCallback@12()+ 0x20字节
comdlg32.dll!CFileOpenSave :: _ NotifyFileOk()+ 0x3d bytes
comdlg32.dll!CFileOpenSave :: _ CleanupDialog()+ 0x46c2 bytes
comdlg32.dll!CFileOpenSave :: _ HandleOkAndClose()+ 0x3a bytes
comdlg32.dll!CFileOpenSave :: _ OnCommandMessage()+ 0xf432字节 comdlg32.dll!CFileOpenSave :: s_OpenSaveDlgProc()+ 0x1f42字节 user32.dll!_InternalCallWinProc@20()+ 0x23 bytes
user32.dll!_UserCallDlgProcCheckWow@32()+ 0xa9 bytes
user32.dll!_DefDlgProcWorker@20()+ 0x7f字节 user32.dll!_DefDlgProcW@16()+ 0x22 bytes