我有一个表格可以根据FormClosing
以不同的方式处理CloseReason
事件。例如,我正在最小化CloseReason.UserClosing
上的表单当我从WCF服务调用返回特定值并且我从通知图标contextmenu {{1}调用Application.Exit()
时,我以编程方式调用该事件。在其他一些条件中关闭应用程序的事件。
虽然我的应用程序按预期工作到现在为止,但在调用ItemClicked
时始终提升FormClosing
事件,但在我做了一些更改后,它的行为并不像那样。大多数情况下,应用程序关闭时不会引发事件,并且几次获取事件就会执行事件上的代码(数据库工作,通知图标处理)而不退出表单。
这怎么可能发生?
答案 0 :(得分:12)
是的,这是可能的。 Application.Exit()方法迭代Application.OpenForms集合中的表单以调用它们的OnFormClosing()方法。 Winforms中存在一个错误,使该集合失去了对开放表单的跟踪。此代码演示了它:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnHandleCreated(EventArgs e) {
// Set breakpoint here:
base.OnHandleCreated(e);
}
protected override void OnMouseDown(MouseEventArgs e) {
this.ShowInTaskbar = !this.ShowInTaskbar;
MessageBox.Show(string.Format("There are {0} open forms", Application.OpenForms.Count));
Application.Exit();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
MessageBox.Show("you won't see this");
base.OnFormClosing(e);
}
}
单击表单以触发错误。请注意它如何报告0个打开的表单以及您从未看到OnFormClosing中显示的消息框。
它是ShowInTaskbar属性的赋值导致它。有几个这样的属性,我选择了ShowInTaskbar,因为当你有NotifyIcon时,你可能会使用它。 RightToLeft是另一个。这些属性是特殊的,因为只有在使用本机CreateWindowEx()api函数创建窗口时才能指定它们。更改它们需要Winforms做一些非常英雄的事情,它会破坏窗口并重新创建它。不幸的是,这也会触发错误,破坏窗口也会从OpenForms集合中删除表单,并忘记将其添加回来。
将OnHandleCreated()方法从此代码段复制/粘贴到表单中,并在其上设置断点。首次创建窗口时,它必须触发一次。当它再次触发并因此调用错误场景时,您可以查看调用堆栈以查看类中的哪些代码触发它。您必须禁用该代码并找到另一种方法。在构造函数中设置ShowInTaskbar属性很好,只有在创建窗口后分配它时才会变坏,就像在Load事件处理程序中一样。
答案 1 :(得分:1)
Form.Closed和Form.Closing事件不会引发 调用Application.Exit方法退出应用程序。如果你 在必须执行的这些事件中都有验证码, 您应该单独为每个打开的表单调用Form.Close方法 在调用Exit方法之前。
修改强>
由于您使用FormClosing
,在这种情况下,您可能应该尝试使用Exit
的重载,这可能有助于确定取消退出的表单并帮助您进一步检查问题。