【问题标题】:Catch an Exception thrown by another form捕获另一个表单抛出的异常
【发布时间】:2012-01-12 22:35:22
【问题描述】:

我正在尝试这样做:

我正在创建另一个表单,它的 FormClosed 方法会引发异常,应该被主表单捕获。

主窗体:

try
    {
        frmOptions frm  = new frmOptions();
        frm.ShowDialog();                        
    }
catch(Exception)
    {
        MessageBox.Show("Exception caught.");
    }

frmOptions:

private void frmOptions_FormClosed(object sender, FormClosedEventArgs e)
{
    throw new Exception();
}

调试器停止异常并显示以下消息:

用户代码未处理异常

为什么?我在创建它的对象的所有者中捕获了异常。有人有想法吗?

【问题讨论】:

  • 请不要将C#放在标题中。这就是标签的用途。
  • 我不明白你描述的问题。我认为问题确实存在,因为 frmOptions 在不同的线程上运行,但显然情况并非如此。我能够捕捉到没有问题的异常。我针对 .NET 2 和 4 进行了测试。
  • @Icarus:转到调试器 -> 异常 -> 全部重置。然后再试一次,你会得到用户代码未处理的异常。
  • @makmiler:做到了。相同的非问题。
  • @Icarus 好吧,我使用 VS 2010 和 .net 4,所以它发生了。其他人也有同样的错误。为什么你没有看到消息,我真的不知道。

标签: c# winforms exception exception-handling


【解决方案1】:

我认为这行不通,新表单没有在您上面的代码上下文中运行,它只是由它启动。如果您检查堆栈跟踪中抛出的异常,您不应该在其中看到上面的代码,因此它无法捕获异常。

更新:我刚刚创建了一个测试项目并进行了尝试。 stacktrace 对原始表单一无所知。如果您想捕获未处理的异常,您可能需要查看这个问题Unhandled Exception Handler in .NET 1.1

【讨论】:

  • “它只是被它启动”是什么意思?对象是在创建它的表单的对象空间中创建的。如果我打开“不要在未处理的异常上停止”,则异常被捕获在主窗体的 try/catch 块中。但这也是一种“托管”异常处理。问题是为什么调试器认为它没有问题?
  • 正如 Renato 在对他们的回答的评论中提到的那样,新表单在单独的 UI 线程中运行,即使它是以模态方式启动的。 frmOptions 中的错误在其堆栈跟踪中没有对启动表单的任何引用
  • 那么您将得到 ThreadException,而不是未处理的用户代码异常。我不相信是这样的,因为如果你在未处理的用户代码上关闭 debugger-Exceptions-Stop,主窗体的 try/catch 块实际上会捕获异常。
  • @makmiler 我做不到,异常不会靠近调用表单
【解决方案2】:

您可以从 program.cs 处理项目中的所有异常

static class Program
        {

            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException;

                Application.ThreadException += Application_ThreadException;
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);         
                Application.Run(new MainMDI());              
            }
            static void Application_ThreadException(Object sender, ThreadExceptionEventArgs e)
            {
                MessageBox.Show(e.Exception.Message, "Application.ThreadException");
            }

            static void AppDomain_UnhandledException(Object sender, UnhandledExceptionEventArgs e)
            {
                MessageBox.Show(((Exception)e.ExceptionObject).Message, "AppDomain.UnhandledException");
            }
        }

【讨论】:

  • 谢谢你,但是,这不是我要问的。
【解决方案3】:

您可以按以下方式执行此操作:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 form2 = new Form2(this);
        form2.Show();
    }

    public void HandleForm2Exception(Exception ex)
    {
        MessageBox.Show("EXCEPTION HAPPENED!");
    }
}

在 Form2.cs 上

public partial class Form2 : Form
{
    private Form1 form1;

    public Form2(Form1 form1) : this()
    {
        this.form1 = form1;
    }

    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_FormClosed(object sender, FormClosedEventArgs e)
    {
        try
        {
            throw new Exception();
        }
        catch (Exception ex)
        {
            if(this.form1 != null)
                this.form1.HandleForm2Exception(ex);
        }
    }
}

【讨论】:

  • 是的,不错的技巧,但不是。这不是这里的问题。请再次阅读我的问题:)
  • makmiler,碰巧您的第二个表单在不同的 ui 线程上下文中运行,这就是您无法直接捕获此异常的原因,这就是 Glenn Slaven 的回答非常有意义的原因。 @this.__curious_geek,你为什么不推荐它?
  • @Renato Gama,如果是这样,那为什么在未处理的用户代码上关闭 debugger-Exceptions-Stop,主窗体的 try/catch 块实际上会捕获异常?跨度>
  • @makmiler,我无法重现您的步骤!你到底做了什么?
【解决方案4】:

您为什么要尝试从一种形式向另一种形式抛出异常? "Don't throw new Exception()"

如果您想让主表单知道选项表单已关闭,您可以在主表单上设置一个从选项表单设置的标志。

【讨论】:

  • 我知道。我在问为什么调试器作为未处理的用户代码停止在异常上,事实上,表单的创建是在 try/catch 块中,如果您选择在此类用户代码上停止调试器,异常最终会被捕获。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 2010-10-03
  • 1970-01-01
  • 2011-06-25
相关资源
最近更新 更多