代码之家  ›  专栏  ›  技术社区  ›  BillW

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

  •  0
  • BillW  · 技术社区  · 16 年前

    有没有 更好的方法 要在用户选择退出WinForms程序后处理执行某项任务,请执行以下操作:

    [编辑1: 回应Nobugz的评论 ] 在这种情况下,窗体上没有ControlBox 当用户选择关闭窗体时会发生什么情况,这是一个放置一级间接寻址的原因。

    [编辑2: 回应截至1月20日格林尼治标准时间+7 18:35的所有评论 ] 也许使用淡出主窗体是一个简单的例子 当应用程序关闭时,您可能需要做的事情:用户无法与之交互:这显然与用户终止应用程序的决定有关。[编辑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中启动一个主窗体):在主窗体的FormClosing事件处理程序中:

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

      a.CloseReason是任何其他CloseReason.ApplicationExitCall

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

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

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

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

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

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

      2. 运行一个计时器来做一些特殊的事情。

      3. 当计时器代码中的内部测试检测到“特殊任务”完成时,它调用application.exit

    3 回复  |  直到 16 年前
        1
  •  7
  •   Svish    16 年前

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

    非常快速的任务

    • 只需在关闭事件处理程序中执行该任务。

    速度不太快,但速度不太慢

    • 使用关闭事件处理程序中的任务创建一个非后台线程(这样在应用程序退出时不会关闭该线程)。
    • 让应用程序退出。表单将消失,等等,但是这个过程将一直运行直到任务完成。
    • 只需记住在工作线程中处理异常等。如果用户在任务完成之前重新打开应用程序,请确保不会发生故障。

    较慢的任务

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

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

    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
    }
    
        2
  •  2
  •   Dave Swersky    16 年前

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

        3
  •  0
  •   Jeremy McGee    16 年前

    几个要点:

    • 我想问一下是否需要一个计时器:由于应用程序无论如何都在退出,并且用户不会因此期望UI是响应的,为什么不简单地在UI线程上执行清理代码呢?正如@dave swersky建议的那样,在清理过程中稍微打开一个通知窗口是有礼貌的。

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