繁体   English   中英

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

[英]WPF exception thrown in eventhandler is swallowed?

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

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

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

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

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

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

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

编辑1

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

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

在我的计算机上,对于上述两个项目,ButtonA会显示一个消息框,ButtonB(选择文件后)则不会。 永远。 甚至无论是否打开“调试非托管代码”。

编辑2

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

其他机器上的例外情况

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

在我的机器上例外

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

这应该与此设置有关:

边界交叉异常设置

但是,打开/关闭此选项无效,即使重新启动VS2012并删除临时文件 (以及项目中的bin / obj目录), 还原默认值等

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

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

谷歌搜索,冲浪等等我最终在这里这里结束。 现在我很清楚如何在另一个调度程序上处理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方法,我们可以从那里获取它。

如果你这样连线,你会发现它正在被处理
仍然不确定为什么它会逃避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获得一个调用堆栈。
我在10分钟内得到了一个电话堆栈。

OP做了三个无效的假设,即使经过长时间的讨论也无法理解

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

回调中的第一行
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 bytes
comdlg32.dll!CFileOpenSave :: _ NotifyFileOk()+ 0x3d bytes
comdlg32.dll!CFileOpenSave :: _ CleanupDialog()+ 0x46c2字节
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
user32.dll!_UserCallDlgProcCheckWow@32()+ 0xa9个字节
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