捕获块未捕获异常

5
我有一个子表单,在Load事件处理程序中故意抛出ApplicationException(用于测试目的)。父表单将ChildForm.Show()方法包装在Try...Catch ex As Exception块中。当在Visual Studio 2008(.net 3.5 sp1)中进行调试时,所有工作都按预期进行。但是,当我在Visual Studio之外运行它时,似乎会跳过Catch块,并发生未处理的异常。您有任何想法吗?
谢谢。
示例代码:
Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim f2 As Form2

        f2 = New Form2

        Try
            MessageBox.Show("Opening form 2")
            f2.ShowDialog()
        Catch ex As Exception
            f2.Close()
            MessageBox.Show("Form 2 closed.")
        End Try
    End Sub

End Class

Public Class Form2

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Throw New ApplicationException("Test Form_Load")
    End Sub

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
    End Sub

End Class

堆栈跟踪:

System.ApplicationException:
在 UnhandledExceptionTest2\WindowsApplication1\Form2.vb 的 WindowsApplication1.Form2.Form2_Load(Object sender, EventArgs e) 处发生错误
System.Windows.Forms.Form.OnLoad(EventArgs e)
System.Windows.Forms.Form.OnCreateControl()
System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
System.Windows.Forms.Control.CreateControl()
System.Windows.Forms.Control.WmShowWindow(Message& m) 在
System.Windows.Forms.Control.WndProc(Message& m) 处
System.Windows.Forms.ScrollableControl.WndProc(Message& m) 在
System.Windows.Forms.ContainerControl.WndProc(Message& m) 在
System.Windows.Forms.Form.WmShowWindow(Message& m) 在
System.Windows.Forms.Form.WndProc(Message& m) 处
System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 在
System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 处
System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

是的 - 正如所描述的那样,它很模糊... - Andrew Flanagan
4个回答

11

Form.Load事件与Windows Forms中的大多数其他事件的行为相同。在此情况下,它由消息循环分派,当Windows发送WM_SHOWWINDOW消息时发生。消息循环中有一个异常处理程序,防止未捕获的异常终止消息循环。该异常处理程序引发Application.ThreadEvent事件。默认事件处理程序显示未处理异常对话框。

简而言之,在您的按钮单击处理程序中无法捕获在Load事件中引发的异常。除了在Load事件处理程序本身中捕获和处理异常(这很难做到正确),我建议您向表单添加一个公共方法,例如Initialize()。将代码从Load事件移动到该方法中。在调用Show()方法后调用Initialize(),异常现在可以被您捕获。


+1 谢谢!可惜只有一个糟糕的解决方法... 更多的代码 = 更多的错误 ;-) - Vincent Van Den Berghe
1
我编程多年,使用WinForms,这是我第一次遇到这个问题。 - AMissico

1

我有同样的问题。最终我做的是捕获所有异常。在C#中:

Application.ThreadException += new ThreadExceptionEventHandler(MyHandler);

然后显示表单。

如果有更好的解决方案,我很乐意听取意见。


0
新窗口有自己的线程,正在进行自己的加载。为了验证这一点,您可以在 Form2_Load 中尝试放入几秒钟的 Thread.Sleep,然后再出现异常。您的主线程窗口应该在出现异常之前继续执行。

可以理解,但为什么在 Visual Studio 中运行代码与在 VS 外部运行时表现不同呢? - DCNYAM
哦,我错过了它调用的是 ShowDialog 而不是 Show,所以它应该会阻塞。那就有点令人困惑了 :-( - Yuliy
当我在VS之外运行程序时,使用“附加到进程...”工具,并打开线程和调用堆栈窗口,我观察到Form2_Load事件正在主线程上运行,并且调用堆栈显示Form1_ButtonClick调用Form2_Load。然而,这种行为仍然存在。 - DCNYAM
请查看nobugz和mgilman的评论,因为他们似乎在这里走在了正确的轨道上。 - Yuliy

0

对于 C# 部分我很抱歉(我不知道 Vb 语法)

你是在做类似这样的事情吗:

  ChildForm child = new ChildForm();
  try {
      child.Show();
  }
  catch(Exception ex)
  {.....}

如果是这样的话,我相信Load事件会发生在New上,而不是Show();(Show会触发Activate)。

当我在调试器中逐步执行时,Load事件会在Show()上发生。 - DCNYAM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接