【C#】Form.Closingイベントの制御

ウィンドウアプリケーションで「Alt + F4」といったキー操作により
画面が閉じられるのを制御するにWndProcメソッドをオーバーライドするのが
普通だと思い込んでいたのですが、
.NET Framework 2.0以降であればCloseReasonプロパティを使用すればよりシンプルにできました。


CloseReasonプロパティについて

CloseReasonプロパティの内容については以下の通りです。


列挙体 説明
ApplicationExitCall Application.Exitメソッドが呼び出された。
FormOwnerClosing 呼び出し元のフォーム画面が閉じられようとしている。
MdiFormClosing 呼び出し元のMDI親フォームが閉じられようとしている。
None なんで閉じられようとしているのかわかんね┐(´ー`)┌
TaskManagerClosing タスクマネージャーにによってアプリが終了させられようとしている。
UserClosing ユーザ操作(×ボタンクリック、Alt+F4押下etc…)によって画面が閉じられようとしている。
※注意点有
WindowsShutDown OSのシャットダウン処理によってアプリが終了させられようとしている。

FormOwnerClosingの注意点について

FormOwnerClosingの説明は公式リファレンスに以下のように書かれています。

ユーザーが、フォーム ウィンドウの [閉じる] ボタンを押す、ウィンドウのコントロール メニューの [閉じる] をクリックする、Alt キーと F4 キーを同時に押すなどの方法で、ユーザー インターフェイス (UI) を通じてフォームを閉じようとしています。

しかし、Form.Closeメソッドを実行した時も「UserClosing」として処理される為、
フラグ管理を行う必要がありそうです…(;´Д`)

Closeメソッド内の処理

Form.Closeメソッドのコードを見たらしっかりとUserClosingをセットしていました…

public void Close() {

    if (GetState(STATE_CREATINGHANDLE))
        throw new InvalidOperationException(SR.GetString(SR.ClosingWhileCreatingHandle, "Close"));

    if (IsHandleCreated) {
        closeReason = CloseReason.UserClosing;
        SendMessage(NativeMethods.WM_CLOSE, 0, 0);
    }
    else{
        // MSDN: When a form is closed, all resources created within the object are closed and the form is disposed.
        // For MDI child: MdiChildren collection gets updated (VSWhidbey# 368642 & 93550)
        Dispose();
    }
}

サンプルコード

Form.Closeメソッドを呼ぶ前にフラグを操作しているだけの簡単なプログラムです。

bool userClosingFlag = true;

/// <summary>
/// フォーム閉じる際にイベント検知するやーつ
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    switch (e.CloseReason)
    {
        case CloseReason.ApplicationExitCall:
            MessageBox.Show("ApplicationExitCall");
            break;
        case CloseReason.FormOwnerClosing:
            MessageBox.Show("FormOwnerClosing");
            break;
        case CloseReason.MdiFormClosing:
            MessageBox.Show("MdiFormClosing");
            break;
        case CloseReason.None:
            MessageBox.Show("None");
            break;
        case CloseReason.TaskManagerClosing:
            MessageBox.Show("TaskManagerClosing");
            break;
        case CloseReason.UserClosing:
            // Form.Closeメソッドでも「UserClosing」判定となる。
            if (userClosingFlag)
            {
                MessageBox.Show("UserClosing");
            }
            else
            {
                MessageBox.Show("Form.Close");
            }
            break;
        case CloseReason.WindowsShutDown:
            MessageBox.Show("WindowsShutDown");
            break;
        default:
            break;
    }
}
/// <summary>
/// 閉じるボタン押下時イベント
/// </summary>
/// <param name="sender">イベント送信元</param>
/// <param name="e">イベント引数</param>
private void Button1_Click(object sender, EventArgs e)
{
    userClosingFlag = false;
    this.Close();
}

実行結果

実行結果は以下の通りです。

Alt+F4押下時

ボタン押下時

キー制御を行うよりシンプルにコーディングできるので多少は使えるのかな…(=゚ω゚)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です