【问题标题】:How to fire FormClosing for ownerless forms on red X exit?如何在红色 X 退出时为无主表单触发 FormClosing?
【发布时间】:2025-12-03 11:40:02
【问题描述】:

我有一个包含多个表单的小应用程序,每个表单都会在 FormClosing 事件期间保存其窗格布局。

当主窗体最小化时,某些窗体需要保留在屏幕上,因此它们以 form.Show() 无主打开,而不是 form.Show(this)

但这会影响FormClosing 的行为 - 当用户使用红色 X 退出时,FormClosing 事件不会为无主表单触发。

Application.Exit() 确实可以根据需要工作,但取消主窗体中的 FormClosing 事件并调用 Application.Exit() 会导致 FormClosing 在除无主窗体之外的所有内容上被调用两次。

我可能会在主窗体的 FormClosing 事件中迭代 OpenForms 并保存需要保存的任何内容,但这似乎有点 hack。有没有办法让 X 的行为方式与 Application.Exit() 相同?

下面的代码演示了这个问题:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        this.Text = "Main";

        Form ownedForm = new Form { Text = "Owned" };
        ownedForm.FormClosing += (s, e) => { System.Diagnostics.Debug.WriteLine("FormClosing owned form"); };
        ownedForm.Show(this);

        Form ownerlessForm = new Form { Text = "Ownerless" };
        ownerlessForm.FormClosing += (s, e) => { System.Diagnostics.Debug.WriteLine("FormClosing ownerless form"); };
        ownerlessForm.Show();

        this.FormClosing += (s, e) =>
        {
            System.Diagnostics.Debug.WriteLine("FormClosing main form");

            // fix below doesn't work as needed!
            //if (e.CloseReason == CloseReason.UserClosing)
            //{
            //    e.Cancel = true;
            //    Application.Exit();
            //}
        };
    }
}

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    在主窗体的FormClosing 处理程序中添加一个事件处理程序,以在主窗体关闭时关闭无主窗体:

    ownerlessForm.Show(); //right after this line that you already have
    FormClosing += (s, e) => ownerlessForm.Close(); //add this
    

    这将确保它们被优雅地关闭,并让它们的关闭事件运行,而不是让主线程结束并在不让这些表单优雅地关闭的情况下拆除进程。

    【讨论】:

    • 很好的答案,谢谢 - 知道红色 X 出口实际上是无主表单的强制退出,一切都变得更加清晰。
    • @jlmt 好吧,更有效地关闭主窗体意味着应用程序的消息循环结束,当它结束时,Main 方法结束,当它结束时,最后剩下的前台线程结束。当这种情况发生时,整个过程就会被拆除。问题是,在任何时候都没有向其他表单发送关闭消息;这段代码改变了这一点。