吞下了在事件处理程序中抛出的WPF异常?

时间:2013-10-02 15:24:08

标签: c# .net wpf xaml exception-handling

当我在事件处理程序中抛出异常时,不会调用异常处理程序吗?

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

的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 questionthis question,但强制32位或64位甚至“任何CPU”都不起作用。此外,在设置任何these four(!)处理程序时,如果在事件中抛出异常,则不会调用它们。 this article也无济于事。

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

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

另外:我对WPF很新,可能是问题:P

的一部分

修改1

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

  1. Simple(10Kb)
  2. Extended(10Kb)
  3. 在我的计算机上,对于上述两个项目,ButtonA会显示一个消息框,ButtonB(选择文件后)则不会。永远。即使打开或未打开“调试非托管代码”,也不会。

    修改2

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

    Exception on other machine

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

    Exception on my machine

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

    这应该与此设置有关:

    Boundary crossed exception settings

    但是,打开/关闭此选项无效,即使重新启动VS2012和deleting temp files(以及项目中的bin / obj目录),restoring defaults etc也是如此。

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

2 个答案:

答案 0 :(得分:2)

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

谷歌搜索,浏览SO等我最终结束了herehere。现在我很清楚如何在另一个调度程序上处理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做出了三个无效的假设,即使经过长时间的讨论也无法理解

  
      
  1. 被吞下的例外   它没有被吞没,只是越过他未被捕获的异常处理程序   我的代码证明了,但OP没有遵循
  2.   
  3. 解决方案没有无人代码
      错误的OpenFileDialog是非托管代码
  4.   
  5. 从托管代码中抛出异常   又错了   异常是从非托管代码的回调中抛出的
  6.   

回调中的第一行
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