VB.NET中关闭Form1导致Form2的DialogResult变为Cancel的问题
问题:关闭Form1后Form2的DialogResult自动变为Cancel是否属于BUG?
我创建了两个Form窗体,分别通过Show和ShowDialog方法显示:Form1用作Logo展示,显示并停留3秒;Form2为登录窗口,以模态方式显示等待用户登录。但在关闭Form1后,发现Form2的DialogResult变为了Cancel,这是否属于BUG?
相关代码如下:
Private WithEvents f1 As Form Private WithEvents f2 As Form Private WithEvents bg As System.ComponentModel.BackgroundWorker Public Sub Run() Try bg = New System.ComponentModel.BackgroundWorker f1 = New Form f1.Name = "Form1" f1.Show() Console.WriteLine("Show Form1 and stay 3 seconds") bg.RunWorkerAsync() f2 = New Form f2.Name = "Form2" Console.WriteLine("Show Form2 (ShowDialog)") Dim rlt = f2.ShowDialog() If rlt = DialogResult.Cancel Then Console.ReadKey() End If Catch ex As Exception End Try End Sub Private Sub bg_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bg.DoWork Dim stw = Stopwatch.StartNew Do Application.DoEvents() Loop Until stw.ElapsedMilliseconds > 3000 End Sub Private Sub bg_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bg.RunWorkerCompleted Console.WriteLine("Form2's DialogResult = {0}", f2.DialogResult) f1.Close() Console.WriteLine("After Form1 close, Form2's DialogResult changed to ({0}). WHY?", f2.DialogResult) End Sub
解答:这不是BUG,是WinForms的默认行为
当WinForms应用中最后一个非模态窗体被关闭时,系统会自动触发Application.Exit()逻辑,这个操作会强制关闭所有正在显示的模态窗体,同时将它们的DialogResult设置为Cancel。
在你的代码里,Form1是唯一的非模态窗体,执行f1.Close()后,系统检测到没有剩余的非模态窗体,就触发了Application.Exit(),导致正在显示的模态窗体Form2被强制关闭,DialogResult被自动设为Cancel。
另外,你用BackgroundWorker配合Application.DoEvents()的实现方式存在风险:Application.DoEvents()会打乱正常的消息循环,容易引发线程安全问题和UI异常。更合理的实现方式是使用WinForms的Timer控件来控制Form1的关闭,避免消息循环混乱:
Private WithEvents f1 As Form Private WithEvents f2 As Form Private WithEvents closeTimer As System.Windows.Forms.Timer Public Sub Run() Try f1 = New Form f1.Name = "Form1" f1.Show() Console.WriteLine("Show Form1 and stay 3 seconds") closeTimer = New System.Windows.Forms.Timer() closeTimer.Interval = 3000 closeTimer.Start() f2 = New Form f2.Name = "Form2" Console.WriteLine("Show Form2 (ShowDialog)") Dim rlt = f2.ShowDialog() If rlt = DialogResult.Cancel Then Console.ReadKey() End If Catch ex As Exception End Try End Sub Private Sub closeTimer_Tick(sender As Object, e As EventArgs) Handles closeTimer.Tick closeTimer.Stop() Console.WriteLine("Form2's DialogResult = {0}", f2.DialogResult) f1.Close() Console.WriteLine("After Form1 close, Form2's DialogResult changed to ({0}).", f2.DialogResult) End Sub
改用Timer后,因为逻辑在主线程执行,不会干扰消息循环;同时只要Form2这个模态窗体还在显示,系统不会触发Application.Exit(),Form1关闭后Form2的DialogResult也不会被强制修改。
内容的提问来源于stack exchange,提问作者ROY
相关产品推荐
相关产品推荐

