WinForms:为什么从RunMessageLoopInner调用Dispose?

时间:2015-09-07 15:32:37

标签: c# winforms exception-handling

我遇到过以下情况。在显示MDI子项的大型应用程序中,子窗体中的异常也会关闭父窗体。

我正在尝试捕获异常并以特殊错误形式显示错误消息。期望的行为是在没有处理父表单的情况下捕获异常。在子表单中,我有一个触发异常的按钮

 throw new ApplicationException("test");

如果我将断点放入主窗体(MDI父级)Dispose方法

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose(disposing);
}

我得到以下调用堆栈

myApp.dll!myForm.Dispose(bool disposing)
System.dll!System.ComponentModel.Component.Dispose()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadWindows.Dispose()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.DisposeThreadWindows()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.Dispose(bool postQuit)
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reasion, System.Windows.Forms.ApplicationContext context)
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reasion, System.Windows.Forms.ApplicationContext context)
System.Windows.Forms.dll!System.Windows.Forms.Application.Run()

处理 true

之后我想要捕获的异常确实在顶级try-catch语句中被捕获但是 mdi父表单已经关闭(为什么?)

这里有一些代码显示了我的顶级try-catch是如何工作的:

public class MainApplication
{
    [STAThread]
    static void Main(string[] args)
    {
        Application.ThreadException += MyThreadExceptionHandler;
        try
        {
            OurMain(args);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message + "\n" + ex.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }
    }

    private static void MyThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message + "\n" + e.Exception.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
    }

    private static void OurMain(string[] args) 
    {
        //run the application
    }

}

我的问题在这里,我正在寻找解决问题的策略,并了解为什么MDI父表格正在关闭(最后阻止它关闭)。

到目前为止,我认为我知道:

  • 我想这不是一个线程问题(顺便说一句。我也处理ThreadException事件并且什么都没有),因为我可以在UI线程中捕获异常。

注意:我已经以非常一般的方式提出了这个问题。请告诉我哪些具体信息与您相关,以便能够回答这个问题。

我的具体案例中的解决方案:

在我的情况下,解决方案不仅要处理Application.ThreadException,还要使用this answer中描述的其他选项。在我的情况下,处理Dispatcher.CurrentDispatcher.UnhandledException完成了这项工作。 Application.ThreadException似乎只适用于纯WinForms,但我封装了一个Web View,并且绑定到Web View触发了异常,Application.ThreadException没有对此做出反应。

1 个答案:

答案 0 :(得分:0)

当发生错误时,异常将“冒泡”代码层次结构,直到它被捕获(使用Try / Catch)或者到达顶部。

当它到达顶部(在调试中)时,应用程序只是关闭 - 关闭所有打开的表单。

如果运行.exe,您将看到标准消息:“应用程序中出现未处理的异常”。使用继续/退出按钮。

处理此问题的方法是使用Try / Catch块来捕获预期的错误。

对于到达顶级主函数的异常,它将在表单中冒泡,导致表单被处理(因为表单对象不再在范围内)。表单由表单实例化代码或垃圾收集器处理。这是自动清理内存的所有部分。