如何正确退出C#应用程序?

271

我有一个使用C#编写的已发布应用程序。每当我通过单击红色退出按钮关闭主窗体时,窗体会关闭但整个应用程序不会退出。当我尝试关闭计算机时,发现了这一点,并随后遭受了许多我添加的子窗口和MessageBox警报。

我尝试过Application.Exit,但它仍会调用所有子窗口和警报。我不知道如何使用Environment.Exit,也不知道要放入哪个整数。

此外,每当我的窗体调用FormClosedFormClosing事件时,我都会使用this.Hide()函数来关闭应用程序;这是否会影响我的应用程序行为?


2
不要处理 FormClosed 或 FormClosing。 - SLaks
1
你是说你只是将窗体隐藏而不是关闭它们?这可能是应用程序没有终止的原因,因为它仍然有打开(隐藏)的窗体。 - Xint0
那我应该将所有的 this.Hide() 替换为 this.Close() 吗? - John Ernest Guadalupe
1
你不需要使用Hide()或Close()。 - H H
1
发布有关关闭操作和事件的代码。 - H H
你是否启动了任何后台线程?如果留下任何额外的线程处于活动状态,进程将无法通过任何优雅的方式退出。此外,当关闭“主”表单时,应清除对其他窗体/对话框的任何引用。任何未处理的GUI元素都可能干扰优雅的退出。 - Zenilogix
5个回答

459

来自MSDN:

Application.Exit

通知所有消息队列必须终止,然后在处理完这些消息后关闭所有应用程序窗口。如果您已经调用了Application.Run (WinForms应用程序),则使用此代码停止所有运行中的线程上的所有消息循环,并关闭应用程序的所有窗口。

Environment.Exit

终止此进程并向底层操作系统提供指定的退出代码。如果您正在使用控制台应用程序,则调用此代码。

这篇文章Application.Exit vs. Environment.Exit提供了一个好建议:

您可以通过检查System.Windows.Forms.Application.MessageLoop属性来确定是否已调用System.Windows.Forms.Application.Run。如果为true,则已调用Run,并且可以假定正在执行WinForms应用程序,如下所示。

if (System.Windows.Forms.Application.MessageLoop) 
{
    // WinForms app
    System.Windows.Forms.Application.Exit();
}
else
{
    // Console app
    System.Environment.Exit(1);
}

参考资料:为什么Application.Exit无法正常工作?


3
对我来说,这非常有用。我有一个WinForms应用程序,它有一个参数,可以以静默方式运行,因此不会显示窗体。当窗体隐藏时,Application.Exit()无法退出应用程序,但Environment.Exit(1)效果却很好。 - Dib
10
问题没有提到因错误退出,因此退出代码应为零:Environment.Exit(0)。任何非零值都意味着是一个特定于应用程序的错误代码,可以被脚本用来采取适当的操作。(这是新代码和一个WinForms应用程序,所以在这种情况下不太可能有影响,但对于编写命令行工具的任何人来说了解这一点很重要。) - YipYip
2
Environment.Exit 也可以用于窗体应用程序。 - Badiparmagi
4
如果我理解正确的话,加上一个 return 语句会极大地改善这种方法。据我理解,在 Application.Exit() 后代码将继续执行直到出现一个 return 语句。 - Bighted19
@Bighted19 真的吗?你能详细说明一下这个机制吗? - Scover
@Scover System.Windows.Forms.Application.Exit(): 通知所有消息泵必须终止,并在消息处理完成后关闭所有应用程序窗口。,备注部分说明Exit方法停止所有线程上运行的消息循环,并关闭应用程序的所有窗口。该方法不一定强制应用程序退出。 - undefined

20

我知道这不是你遇到的问题,但造成这种情况的另一个原因是您的应用程序中有一个非后台线程处于打开状态。

using System;
using System.Threading;
using System.Windows.Forms;

namespace Sandbox_Form
{
    static class Program
    {
        private static Thread thread;

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            thread = new Thread(BusyWorkThread);
            thread.IsBackground = false;
            thread.Start();

            Application.Run(new Form());

        }

        public static void BusyWorkThread()
        {
            while (true)
            {
                Thread.Sleep(1000);
            }
        }
    }
}

IsBackgroundfalse 时,它将保持程序一直运行到线程完成,如果你将 IsBackground 设置为 true,线程将不会保持程序的运行。像 BackgroundWorkerThreadPoolTask 这样的东西都在内部使用将 IsBackground 设置为 true 的线程。


10
顺便提一下,每当我的表单调用"formclosed"或"form closing"事件时,我会使用"this.Hide()"函数关闭应用程序。这是否会影响现在应用程序的行为?
简而言之,是的。当主窗体(在"Main"方法中通过"Application.Run"启动的窗体)关闭(而不是隐藏)时,整个应用程序将结束。
如果您希望在主窗体关闭时始终完全终止整个应用程序,那么您应该删除该窗体关闭处理程序。不取消该事件并允许用户在关闭时关闭窗体,您将获得所需的行为。对于所有其他窗体,如果您不打算再次显示该窗体实例,则可以让它们关闭,而不是防止关闭并将其隐藏。如果要重新显示它们,则隐藏它们可能是可以的。
如果您希望能够让用户单击主窗体的"x",但保持另一个窗体保持打开并实际上变成"新"的主窗体,则情况会更加复杂。在这种情况下,您需要隐藏主窗体而不是关闭它,但是您需要添加某种机制来实际上关闭主窗体,以便在您真正想要结束应用程序时。如果这是您所处的情况,请向问题添加更多细节,描述应该和不应该真正结束程序的应用程序类型。

2

只需使用

this.Close();

或者

System.Environment.Exit(1);

-2
在这种情况下,最合适的退出应用程序方式是重写 App.xaml.cs 文件中的 onExit() 方法:
protected override void OnExit(ExitEventArgs e) {
    base.OnExit(e); 
}

2
这允许您在退出事件发生时执行代码,但并不实际导致退出事件发生。 - jpaugh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接