捕获另一个表单抛出的异常
Posted
技术标签:
【中文标题】捕获另一个表单抛出的异常【英文标题】: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,所以它发生了。其他人也有同样的错误。为什么你没有看到消息,我真的不知道。 【参考方案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 块中,如果您选择在此类用户代码上停止调试器,异常最终会被捕获。以上是关于捕获另一个表单抛出的异常的主要内容,如果未能解决你的问题,请参考以下文章
捕获 AuthenticationProvider 中抛出的异常