简体   繁体   English

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

[英]WPF exception thrown in eventhandler is swallowed?

When I throw an exception in an eventhandler the exceptionhandler is not called? 当我在事件处理程序中抛出异常时,不会调用异常处理程序?

Sample code of a stripped down example to start off with: 从以下开始的精简示例的示例代码:

App.xaml 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 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 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 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();
        }
    }
}

I already took a look at this question and this question but forcing either 32 or 64 bit or even "ANY CPU" doesn't work. 我已经看过这个问题这个问题,但强制32或64位甚至“任何CPU”都不起作用。 Also, when setting any of these four (!) handlers up none of them get called when the exception is thrown in the event. 此外,当设置这四个 (!)处理程序中的任何一个时,在事件中抛出异常时,不会调用它们。 Also this article didn't help. 这篇文章也没有帮助。

I am running VS2012 (on Win8, x64), the project is using .Net Framework 4.5). 我正在运行VS2012(在Win8,x64上),该项目正在使用.Net Framework 4.5)。 What am I missing? 我错过了什么? Am I going crazy? 我疯了吗?

For clarity: I'm expecting a messagebox to be shown (which it does when I click ButtonA ), or, actually, the App_DispatcherUnhandledException method being called at all. 为清楚起见:我希望显示一个消息框(当我单击ButtonA时它会显示),或者实际上, App_DispatcherUnhandledException调用的是App_DispatcherUnhandledException方法。 But the method is not called (and thus the messagebox isn't shown) when I click ButtonB . 但是当我单击ButtonB时,不调用该方法( 因此不显示消息框)。 The only difference between ButtonA and ButtonB is that the exception in " A " is not in an eventhandler and the exception in " B " is. ButtonAButtonB之间的唯一区别是“ A ”中的异常不在事件处理程序中,而“ B ”中的异常是。 And, ofcourse, I do select a file in the OpenFileDialog and click "Open" to select it. 并且,当然,我在OpenFileDialog选择一个文件,然后单击“打开”以选择它。 The debugger kicks in and points out the " Does not work!?!? " exception is thrown, then I continue execution and no messagebox is shown. 调试器启动并指出“ 不工作!?!? ”异常被抛出,然后我继续执行并且没有显示消息框。

Also: I am pretty new to WPF, that might be part of the problem 另外:我对WPF很新,这可能是问题的一部分 :P

Edit 1 编辑1

For reference, here are two zipfiles demonstrating the exact problem: 作为参考,这里有两个zipfiles演示确切的问题:

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

On my computer, for both above projects, ButtonA causes a messagebox to be shown, ButtonB (after selecting a file) doesn't. 在我的计算机上,对于上述两个项目,ButtonA会显示一个消息框,ButtonB(选择文件后)则不会。 Ever. 永远。 Not even with or without turning on "debugging unmanaged code". 甚至无论是否打开“调试非托管代码”。

Edit 2 编辑2

So, I ran the same code on another machine and found this out: On the other machine the debugger displays this: 所以,我在另一台机器上运行相同的代码并发现了这一点:在另一台机器上,调试器显示:

其他机器上的例外情况

Note the Exception crossed a native/managed boundary title. 请注意, Exception crossed a native/managed boundary标题。 When I try to resume execution (continue) the exception keeps popping up. 当我尝试恢复执行(继续)时,异常会不断弹出。 My machine, when the debugger kicks in, shows: 当调试器启动时,我的机器显示:

在我的机器上例外

...and then, when I resume execution, the exception disappears in some kind of black hole; ......然后,当我恢复执行时,异常会在某种黑洞中消失; the main form is shown again and nothing happens. 主要形式再次显示,没有任何反应。

This should have to do with this setting: 这应该与此设置有关:

边界交叉异常设置

However, turning this option on/off doesn't help, even with restarting VS2012 and deleting temp files (and bin/obj directories from the project), restoring defaults etc . 但是,打开/关闭此选项无效,即使重新启动VS2012并删除临时文件 (以及项目中的bin / obj目录), 还原默认值等

So... I now know the exception, indeed, has to do with cross-boundaries between managed and unmanaged. 所以......我现在知道异常,实际上与托管和非托管之间的跨界有关。 Now I just need to figure out how to solve this problem so that I can throw the exception in the FileOk event (so that, eventually, my component can throw up in there too). 现在我只需要弄清楚如何解决这个问题,以便我可以在FileOk事件中抛出异常(这样,最终,我的组件也可以在那里抛出)。

Ok, so I solved my problem. 好的,所以我解决了我的问题。

Googling around, surfing SO etc. I eventually ended up here and here . 谷歌搜索,冲浪等等我最终在这里这里结束。 It is now clear to me how the FileOk event is handled on another dispatcher and so the solution is simple: 现在我很清楚如何在另一个调度程序上处理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();
}

This ensures the exception is passed to the correct dispatcher and handled there. 这可以确保将异常传递给正确的调度程序并在那里处理。 The App_DispatcherUnhandledException method is then correctly invoked and we can take it from there. 然后正确调用App_DispatcherUnhandledException方法,我们可以从那里获取它。

If you wire it up like this you will see that it is being handled 如果你这样连线,你会发现它正在被处理
Still not sure why it eludes App_DispatcherUnhandledException 仍然不确定为什么它会逃避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!?!?");
        }
    }
}

Debug 101 is get a call stack. Debug 101获得一个调用堆栈。
I got a call stack in 10 minutes. 我在10分钟内得到了一个电话堆栈。

OP made three invalid assumptions and even after a long discussion does not understand OP做了三个无效的假设,即使经过长时间的讨论也无法理解

  1. Exception was being swallowed 吞噬了例外
    It was not being swallowed it was just getting past his uncaught exception handler My code demonstrated that but OP did not follow 它没有被吞没它只是越过他未被捕获的异常处理程序我的代码证明了但OP没有遵循
  2. Solution has no unmanned code 解决方案没有无人代码
    Wrong again OpenFileDialog is unmanaged code 错误的OpenFileDialog是非托管代码
  3. Exception was being thrown from managed code 托管代码抛出了异常
    Wrong again 又错了
    The exception was being thrown from the callback from unmanaged code 异常是从非托管代码的回调中抛出的

First line in the callback 回调中的第一行
Degbug 101 is get a call stack Degbug 101获得一个调用堆栈

UncaughtExceptionHandler.exe!UncaughtExceptionHandler.MainWindow.MyCanelEventHandler(object sender, System.ComponentModel.CancelEventArgs e) Line 55 C# comdlg32.dll!CFileOpenSave::_NotifyFileOkChangeCallback() + 0x18 bytes comctl32.dll!_DPA_EnumCallback@12() + 0x20 bytes 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 bytes
comdlg32.dll!CFileOpenSave::_NotifyFileOk() + 0x3d bytes comdlg32.dll!CFileOpenSave :: _ NotifyFileOk()+ 0x3d bytes
comdlg32.dll!CFileOpenSave::_CleanupDialog() + 0x46c2 bytes comdlg32.dll!CFileOpenSave :: _ CleanupDialog()+ 0x46c2字节
comdlg32.dll!CFileOpenSave::_HandleOkAndClose() + 0x3a bytes comdlg32.dll!CFileOpenSave :: _ HandleOkAndClose()+ 0x3a bytes
comdlg32.dll!CFileOpenSave::_OnCommandMessage() + 0xf432 bytes comdlg32.dll!CFileOpenSave::s_OpenSaveDlgProc() + 0x1f42 bytes user32.dll!_InternalCallWinProc@20() + 0x23 bytes comdlg32.dll!CFileOpenSave :: _ OnCommandMessage()+ 0xf432 bytes comdlg32.dll!CFileOpenSave :: s_OpenSaveDlgProc()+ 0x1f42 bytes user32.dll!_InternalCallWinProc@20()+ 0x23 bytes
user32.dll!_UserCallDlgProcCheckWow@32() + 0xa9 bytes user32.dll!_UserCallDlgProcCheckWow@32()+ 0xa9个字节
user32.dll!_DefDlgProcWorker@20() + 0x7f bytes user32.dll!_DefDlgProcW@16() + 0x22 bytes user32.dll!_DefDlgProcWorker@20()+ 0x7f bytes user32.dll!_DefDlgProcW@16()+ 0x22 bytes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM