是否有任何情况下Application.Exit()不会引发FormClosing事件?

时间:2012-11-23 09:50:35

标签: c# .net winforms

我有一个表格可以根据FormClosing以不同的方式处理CloseReason事件。例如,我正在最小化CloseReason.UserClosing上的表单当我从WCF服务调用返回特定值并且我从通知图标contextmenu {{1}调用Application.Exit()时,我以编程方式调用该事件。在其他一些条件中关闭应用程序的事件。

虽然我的应用程序按预期工作到现在为止,但在调用ItemClicked时始终提升FormClosing事件,但在我做了一些更改后,它的行为并不像那样。大多数情况下,应用程序关闭时不会引发事件,并且几次获取事件就会执行事件上的代码(数据库工作,通知图标处理)而不退出表单。

这怎么可能发生?

2 个答案:

答案 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)

以及stated here

  

Form.Closed和Form.Closing事件不会引发   调用Application.Exit方法退出应用程序。如果你   在必须执行的这些事件中都有验证码,   您应该单独为每个打开的表单调用Form.Close方法   在调用Exit方法之前。

修改

由于您使用FormClosing,在这种情况下,您可能应该尝试使用Exit的重载,这可能有助于确定取消退出的表单并帮助您进一步检查问题。