我有一个表单,我FormClosing根据不同的方式处理事件CloseReason.例如,当我CloseReason.UserClosing从WCF服务调用返回特定值并且我Application.Exit()从通知图标contextmenu ItemClicked事件调用以在其他一些条件中关闭App 时,我正在以编程方式调用事件来最小化表单.
虽然我的应用程序按预期工作到现在为止,总是FormClosing在Application.Exit()调用时提升事件,但在我做了一些更改之后,它的行为并不像那样.大多数情况下,应用程序关闭时不会引发事件,并且几次获取事件就会执行事件上的代码(数据库工作,通知图标处理)而不退出表单.
怎么会发生这种情况?
Han*_*ant 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);
}
}
Run Code Online (Sandbox Code Playgroud)
单击表单以触发错误.请注意它如何报告0个打开的表单以及您从未看到OnFormClosing中显示的消息框的方式.
它是ShowInTaskbar属性的赋值导致它.有几个这样的属性,我选择了ShowInTaskbar,因为当你有NotifyIcon时,你可能会使用它.RightToLeft是另一个.这些属性是特殊的,因为只有在使用本机CreateWindowEx()api函数创建窗口时才能指定它们.更改它们需要Winforms做一些非常英雄的事情,它会破坏窗口并重新创建它.不幸的是,这也会触发错误,破坏窗口也会从OpenForms集合中删除表单并忘记将其添加回来.
将此代码段中的OnHandleCreated()方法复制/粘贴到表单中,并在其上设置断点.首次创建窗口时,它必须触发一次.当它再次触发并因此调用错误场景时,您可以查看调用堆栈以查看类中的哪些代码触发它.您必须禁用该代码并找到另一种方法.在构造函数中设置ShowInTaskbar属性很好,只有在创建窗口后分配它时才会变坏,就像在Load事件处理程序中一样.