0

ユーザーがWinFormsプログラムを終了することを選択した後に何かをするというタスクを処理するより良い方法はありますか?

[編集 1 : 'NoBugz によるコメントへの応答]この場合、 Form には ControlBox がなく、ユーザーが Form を閉じることを選択したときに何が起こるかについて、1 レベルの間接化を設定する理由があります [/編集 1]

[編集 2: 1 月 20 日 GMT +7 18:35 の時点でのすべてのコメントへの応答]おそらく MainForm のフェードアウトを使用することは、アプリケーションが閉じられているときに何をしたいかの簡単な例です: ユーザーはそれと対話できません:アプリケーションを終了するというユーザーの決定に関連していることは自明です。[/編集 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 で起動された 1 つの MainForm): MainForm の FormClosing イベント ハンドラー:

  1. すぐに終了します (デフォルトの動作をトリガーします: MainForm を閉じてアプリケーションを終了します) 次の場合:

    を。CloseReason はその他の CloseReason.ApplicationExitCall です

    b. 特別なブール変数が true に設定されている場合、または

  2. すぐに終了しない場合: FormClosing への「最初の呼び出し」をキャンセルします。

  3. 次に、ユーザーは MessageBox.Show ダイアログを介して、アプリケーションを終了するか、キャンセルするかを選択します。

    を。もちろん、ユーザーがキャンセルした場合、アプリケーションは「そのまま」残ります。

    b. ユーザーが「終了」を選択した場合:

    1. 特別なブール値のフラグ変数を true に設定します

    2. いくつかの特別なことをするタイマーを実行します。

    3. Timer コードの内部テストで「特別な処理」が行われたことが検出されると、Application.Exit が呼び出されます。

4

3 に答える 3

7

開発者とユーザーの両方としての私の提案:

非常に高速なタスク

  • Closing イベント ハンドラーでタスクを実行するだけです。

それほど速くはありませんが、信じられないほど遅いタスクではありません

  • Closing イベント ハンドラーのタスクを使用して、非バックグラウンド スレッドを作成します (アプリケーションの終了時にシャットダウンされないようにします)。
  • アプリケーションを終了させます。フォームなどはなくなりますが、プロセスはタスクが完了するまで実行され続けます。
  • そのワーカースレッドで例外などを処理することを忘れないでください。また、そのタスクが完了する前にユーザーがアプリケーションを再度開いた場合にクラッシュしないことを確認してください。

遅いタスク

  • Closing イベント ハンドラーで、shutting-down-form を開き、フォーム自体を閉じます。
  • 友好的な進行状況と情報を表示しながら、シャットダウン フォーム内/背後でタスクを実行します。
  • タスクが完了したら、アプリケーションを終了します。

テストされていないサンプルコード。アプリケーションの 1 つで、これと同様のことを行っています。この場合のタスクは、ウィンドウのプロパティ (場所、サイズ、ウィンドウの状態など) をデータベースに格納することです。

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
}
于 2010-01-20T11:49:34.663 に答える
2

これには「間違った」ものは何もありません。私の唯一の推奨事項は、非モーダルウィンドウまたはおそらくシステムトレイの上に通知トースターを上げることによって、プログラムが「シャットダウン」していることをユーザーに知らせることです。

于 2010-01-19T19:33:12.380 に答える
0

いくつかのマイナーなポイント:

  • タイマーの必要性に疑問があります。アプリケーションはとにかく終了しているため、ユーザーはUIが応答することを期待しないので、UIスレッドでクリーンアップコードを実行してみませんか?@Dave Swerskyが提案したように、クリーンアップ中の小さな通知ウィンドウは丁寧です。

  • アプリケーションの終了がWindowsのシャットダウンまたはユーザーのログオフによってトリガーされた場合はどうなりますか?

于 2010-01-19T19:40:01.427 に答える