eventhandler抛出的WPF异常被吞了?

Rob*_*III 4 .net c# wpf xaml exception-handling

当我在事件处理程序中抛出异常时,异常处理程序没有被调用?

从以下开始的精简示例的示例代码:

应用程序.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>
Run Code Online (Sandbox Code Playgroud)

应用程序.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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

主窗口.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>
Run Code Online (Sandbox Code Playgroud)

主窗口.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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经看过这个问题这个问题,但是强制使用 32 位或 64 位甚至“任何 CPU”都不起作用。此外,当设置这四个(!) 处理程序中的任何一个时,当在事件中抛出异常时,它们都不会被调用。同时此文章没有帮助。

我正在运行 VS2012(在 Win8、x64 上),该项目使用 .Net Framework 4.5)。我错过了什么?我要疯了吗?

为清楚起见:我希望显示一个消息框(当我单击时它会显示ButtonA),或者,实际上,完全App_DispatcherUnhandledException调用该方法。但是当我单击 时不会调用该方法(因此不显示消息框)ButtonBButtonA和之间的唯一区别ButtonB是“ A”中的异常不在事件处理程序中,而“ B”中的异常在。而且,当然,我确实在 中选择了一个文件,OpenFileDialog然后单击“打开”来选择它。调试器启动并指出“不起作用!?!? ”异常被抛出,然后我继续执行并且没有显示消息框。

另外:我对 WPF 还很陌生,这可能是问题的一部分 :P

编辑 1

作为参考,这里有两个 zipfile 演示了确切的问题:

  1. 简单(10Kb)
  2. 扩展(10Kb)

在我的计算机上,对于上述两个项目,ButtonA 会导致显示一个消息框,而 ButtonB(选择文件后)不会。曾经。甚至没有打开“调试非托管代码”。

编辑 2

所以,我在另一台机器上运行了相同的代码并发现了这一点:在另一台机器上,调试器显示:

其他机器上的异常

注意Exception crossed a native/managed boundary标题。当我尝试恢复执行(继续)时,异常不断弹出。我的机器,当调试器启动时,显示:

我的机器上的异常

...然后,当我恢复执行时,异常消失在某种黑洞中;主窗体再次显示,没有任何反应。

这应该与此设置有关:

越界异常设置

但是,即使重新启动 VS2012 并删除临时文件(以及项目中的 bin/obj 目录)、恢复默认值等,打开/关闭此选项也无济于事。

所以...我现在知道异常确实与托管和非托管之间的跨界有关。现在我只需要弄清楚如何解决这个问题,以便我可以在FileOk事件中抛出异常(这样,最终,我的组件也可以在那里抛出)。

Rob*_*III 5

好的,所以我解决了我的问题。

谷歌搜索,冲浪等。我最终在这里这里结束。现在我很清楚 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();
}
Run Code Online (Sandbox Code Playgroud)

这确保异常被传递到正确的调度程序并在那里处理。App_DispatcherUnhandledException然后正确调用该方法,我们可以从那里获取它。