延迟应用程序关闭最佳实践?

发布于 2024-08-18 14:07:43 字数 1854 浏览 8 评论 0原文

在用户选择退出 WinForms 程序后,是否有更好的方法来处理执行某些操作的任务:

[编辑 1:响应“NoBugz”的评论 ] 在这种情况下,窗体上没有 ControlBox,并且有理由在用户选择关闭窗体时发生的情况中放置一层间接性[/edit 1]

[edit 2 : 回应截至 20 月 20 日 GMT +7 18:35 的所有评论] 也许使用淡出 MainForm 是一个简单的说明,说明您可能想要执行的操作,因为应用程序是正在关闭:用户无法与之交互:这显然与用户终止应用程序的决定有关。 [/edit 2]

(使用某种形式的线程?)(对多线程应用程序的影响?)(这段代码“味道不好”吗?)

    // 'shutDown is an external form-scoped boolean variable
    //
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        // make sure we don't block Windows ShutDown
        // or other valid reasons to close the Form
        if (e.CloseReason != CloseReason.ApplicationExitCall) return;

        // test for 'shutDown flag set here
        if (shutDown) return;

        // cancel closing the Form this time through
        e.Cancel = true;

        // user choice : default = 'Cancel
        if (MessageBox.Show("Exit Application ?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.OK)
        {
            // user says Exit : activate Timer, set the flag to detect Exit
            timer1.Enabled = true;
            shutDown = true;
        }
    }

摘要:在一个非常标准的 WinForms 应用程序中(在 Program.cs 中启动的一个 MainForm标准方式):在 MainForm 的 FormClosing 事件处理程序中:

  1. 立即退出(触发默认行为:关闭 MainForm 并退出应用程序)如果:

    a. CloseReason 是任何其他 CloseReason.ApplicationExitCall

    b.如果一个特殊的布尔变量设置为 true,或者

  2. 如果没有立即退出:取消对 FormClosing 的“第一次调用”。

  3. 用户然后通过 MessageBox.Show 对话框做出选择,退出应用程序,或取消:

    a.当然,如果用户取消,应用程序将保持“原样”。

    b.如果用户选择“退出”:

    1. 将特殊布尔标志变量设置为 true

    2. 运行一个执行一些特殊操作的计时器。

    3. 当计时器代码中的内部测试检测到“特殊内容”完成时,它会调用 Application.Exit

Is there a better way to handle the task of doing something after the user has chosen to exit a WinForms program than this :

[edit 1 : in response to comment by 'NoBugz] In this case there is no ControlBox on the Form, and there is a reason for putting one level of indirection in what happens when the user chooses to close the Form [/edit 1]

[edit 2 : in response to all comments as of GMT +7 18:35 January 20 ] Perhaps using fading out the MainForm is a simple illustration of what you might want do as the Application is being closed : the user cannot interact with that : it is self-evidently related to the user's decision to terminate the application. [/edit 2]

(use some form of threading ?) (implications for a multi-threaded app ?) (does this code "smell bad" ?)

    // 'shutDown is an external form-scoped boolean variable
    //
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        // make sure we don't block Windows ShutDown
        // or other valid reasons to close the Form
        if (e.CloseReason != CloseReason.ApplicationExitCall) return;

        // test for 'shutDown flag set here
        if (shutDown) return;

        // cancel closing the Form this time through
        e.Cancel = true;

        // user choice : default = 'Cancel
        if (MessageBox.Show("Exit Application ?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.OK)
        {
            // user says Exit : activate Timer, set the flag to detect Exit
            timer1.Enabled = true;
            shutDown = true;
        }
    }

Summary : In a very standard WinForms application (one MainForm launched in Program.cs in the standard way) : in the FormClosing Event handler of the MainForm :

  1. exit immediately (triggering the default behavior : which is to close the MainForm and exit the Application) if :

    a. the CloseReason is anything other CloseReason.ApplicationExitCall

    b. if a special boolean variable is set to true, or

  2. if no immediate exit : cancel the "first call" to FormClosing.

  3. the user then makes a choice, via MessageBox.Show dialog, to Exit the Application, or Cancel :

    a. if the user Cancels, of course, the Application stays "as is."

    b. if the user has chosen to 'Exit :

    1. set the special boolean flag variable to true

    2. run a Timer that does some special stuff.

    3. when the internal test in the Timer code detects the "special stuff" is done, it calls Application.Exit

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不必了 2024-08-25 14:07:43

作为开发人员和用户,我的建议是:

非常快的任务

  • 只需在 Closing 事件处理程序中执行该任务即可。

速度较慢,但​​速度也不算太慢的任务

  • 使用 Closing 事件处理程序中的任务创建一个非后台线程(因此应用程序退出时不会关闭)。
  • 让应用程序退出。表单将消失,等等,但该过程将继续运行,直到任务完成。
  • 只需记住在该工作线程中处理异常等即可。并确保如果用户在任务完成之前重新打开您的应用程序,事情不会崩溃。

较慢的任务

  • 在 Closing 事件处理程序中,打开一个正在关闭的表单并让该表单自行关闭。
  • 执行关闭表单中/后面的任务,同时显示一些友好的进度和信息。
  • 任务完成后退出应用程序。

一些未经测试的示例代码。我们正在我们的一个应用程序中做类似的事情。我们例子中的任务是将窗口属性(位置、大小、窗口状态等)存储到数据库中。

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // If it wasn't the user who asked for the closing, we just close
    if (e.CloseReason != CloseReason.UserClosing)
        return;

    // If it was the user, we want to make sure he didn't do it by accident
    DialogResult r = MessageBox.Show("Are you sure you want this?", 
                                     "Application is shutting down.",
                                     MessageBoxButtons.YesNo, 
                                     MessageBoxIcon.Question);
    if (r != DialogResult.Yes)
    {
        e.Cancel = true;
        return;
    }
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
    // Start the task
    var thread = new Thread(DoTask)
    {
        IsBackground = false,
        Name = "Closing thread.",
    };
    thread.Start();

    base.OnFormClosed(e);
}

private void DoTask()
{
    // Some task to do here
}

My suggestions, both as a developer and a user:

A very fast task

  • Just do the task in the Closing event handler.

A less fast, but not incredibly slow task

  • Create a non-background thread (so it's not shut down when the application exits) with the task in the Closing event handler.
  • Let the application exit. Forms will go away, et cetera, but the process will keep running until the task is done.
  • Just remember to handle exceptions and such in that worker thread. And make sure that things doesn't crash if the user reopens your application before that task is done.

Slower tasks

  • In the Closing event handler, open a shutting-down-form and let the form itself close.
  • Do the task in the/behind the shutting-down-form while displaying some friendly progress and information.
  • Exit application when task is done.

Some untested example code. We are doing something similar to this in one of our applications. The task in our case is to store window properties (location, size, window state, et cetera) to a database.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // If it wasn't the user who asked for the closing, we just close
    if (e.CloseReason != CloseReason.UserClosing)
        return;

    // If it was the user, we want to make sure he didn't do it by accident
    DialogResult r = MessageBox.Show("Are you sure you want this?", 
                                     "Application is shutting down.",
                                     MessageBoxButtons.YesNo, 
                                     MessageBoxIcon.Question);
    if (r != DialogResult.Yes)
    {
        e.Cancel = true;
        return;
    }
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
    // Start the task
    var thread = new Thread(DoTask)
    {
        IsBackground = false,
        Name = "Closing thread.",
    };
    thread.Start();

    base.OnFormClosed(e);
}

private void DoTask()
{
    // Some task to do here
}
玻璃人 2024-08-25 14:07:43

我不认为这有什么“问题”。我唯一的建议是通过在系统托盘上方升起非模式窗口或通知烤面包机,让用户知道程序正在“关闭”。

I don't see anything "wrong" with this. My only recommendation would be to let the user know that the program is "shutting down" by raising a non-modal window or perhaps a notification toaster above the system tray.

盗梦空间 2024-08-25 14:07:43

几个小要点:

  • 我质疑是否需要计时器:因为应用程序无论如何都会退出,因此用户不会期望 UI 能够响应,为什么不简单地执行清理代码用户界面线程?正如 @Dave Swersky 所建议的,在清理过程中显示一个小通知窗口是有礼貌的。

  • 如果应用程序退出是由 Windows 关闭或用户注销触发的,会发生什么情况?

A couple of minor points:

  • I'd question the need for a timer: as the application is exiting anyway, and the user won't therefore expect the UI to be responsive, why not simply do the clean-up code on the UI thread? As suggested by @Dave Swersky, a little notification window during cleanup would be polite.

  • What happens if the application exit is triggered by a Windows shutdown or a user logoff?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文