延迟申请关闭最佳做法?

时间:2010-01-19 19:17:02

标签: c# winforms formclosing

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

[编辑1:以响应'NoBugz的评论] 在这种情况下,表单上没有ControlBox ,并且有理由放置一个级别的当用户选择关闭表单[/ edit 1]

时发生的事件的间接

[编辑2:回应GMT + 7月20日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并退出应用程序),如果:

    一个。 CloseReason是其他任何CloseReason.ApplicationExitCall

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

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

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

    一个。如果用户取消,当然,应用程序保持“原样”。

    湾如果用户选择了“退出:

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

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

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

3 个答案:

答案 0 :(得分:7)

我的建议,无论是作为开发人员还是用户:

一项非常快速的任务

  • 只需在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
}

答案 1 :(得分:2)

我没有看到任何“错误”。我唯一的建议是让用户知道该程序是通过在系统托盘上方提升非模态窗口或通知烤面包机而“关闭”。

答案 2 :(得分:0)

一些小问题:

  • 我怀疑需要一个计时器:因为应用程序正在退出,并且用户因此不希望UI响应,为什么不简单地在UI线程上执行清理代码?正如@Dave Swersky所建议的那样,清理过程中的一个小通知窗口会很有礼貌。

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