web-dev-qa-db-ja.com

フォームクロージングイベントの「e.Cancel」

FormClosingイベントを使用する場合、コード_e.Cancel = true;_は機能するのに、new CancelEventArgs().Cancel = true;は機能しないのはなぜですか?

_private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;

    new CancelEventArgs().Cancel = true;
}
_
11
user635409

このイベントは、Winforms配管コードによって発生します。カスタムイベントハンドラーがデフォルトの動作を変更したいことを確認できる唯一の方法は、eオブジェクトを使用することです。新しいCancelEventArgsオブジェクトを作成しても、配管で検出できる副作用はありません。

他に何か問題があります。外部コードの利益のためにイベントが発生し、何が起こっているのかを知らせ、動作を変更するオプションを提供します。ここには外部コードはありません。イベントハンドラーは、実際にはイベントを発生させる同じクラスの一部です。つまり、フォームは独自のイベントをリッスンしています。これに対処するためのはるかに優れた方法があります。イベントを発生させるメソッドをオーバーライドします。このような:

    protected override void OnFormClosing(FormClosingEventArgs e) {
        e.Cancel = true;
        base.OnFormClosing(e);
    }

これで、外部コードがデフォルトの動作をオーバーライドできるようになり、イベントが発生しますafter OnXxxxメソッドが実行されます。また、外部コードで動作をオーバーライドしたくない場合は、2つのステートメントを交換するだけです。

23
Hans Passant

コードはそれが言っていることを正確に実行していると思います。欠けているのはそれを文字通り読むことです。

_e.Cancel_に新しい値を割り当てると、関数のパラメーターとして提供されるeが変更されます。イベントハンドラー関数が終了すると、このFormClosingEventArgsインスタンスは、イベントハンドラー内から加えられた変更を含め、イベントハンドラーを呼び出したすべてのコードで使用できるようになります。この場合、それはほぼ確実にMicrosoftによって作成されたWinformsコードです。

反対に、そのイベントハンドラーがinsideの場合、タイプFormClosingEventArgsの新しいインスタンスを作成し、それに何かを行うと、次のようになります。その情報を発信者に返すものは何もありません。そのためには何かを明示する必要があります。呼び出し元は、イベントハンドラーが完了すると渡されたパラメーターの値を確認しているため、呼び出し元から見たeのコンテンツを新しく作成されたインスタンスに置き換える必要があります。その他の場合、そのような結果は戻り値として提供される場合があります。

一般に、new T()の結果は、あるタイプTに対して、タイプTのインスタンスです。したがって、タイプTのnull以外の変数と同じように、式new T()の結果を操作できます。特定のケースでは、タイプT(具体的には、このように作成されたそのタイプのインスタンス)のプロパティに値を割り当てています。 (コンストラクターが失敗する特殊なケースがありますが、今はそこに行きません。単純な型の場合、それは、プログラムがどのような場合でも実行を継続できないほどの悲惨な状況にあることを意味します。 )

ここで重要なのは、式new T()itselfの結果をどこにも割り当てないと、新しく作成されたインスタンスがスローされることです。ステートメントが完了すると、離れて(技術的にはアクセスできなくなります)。その後、ある時点で、.NETガベージコレクタが起動し、割り当てられたメモリを実際に再利用します。ここを除いて、ある関数に変数を割り当て、別の関数からその関数を呼び出し、最初の関数から2番目の関数に変数を転送することなく、2番目の関数から割り当てられた変数にアクセスしようとすることと実際には何の違いもありません。関係する機能は1つだけです。

イベントハンドラーで2行目のコードのようなことを行うのはかなり珍しいことですが、コンストラクターを呼び出すことで次のような副作用がある場合は、原則としてcanが有効です。遅延読み込みをトリガーするなど、利用しようとしています。

15
a CVn

このコードは確かに動作しますそれをチェックするだけです

protected override void OnFormClosing(FormClosingEventArgs e)
        {            
            base.OnFormClosing(e);
            if (PreClosingConfirmation() == System.Windows.Forms.DialogResult.Yes)
            {
                Dispose(true);
                Application.Exit();
            }
            else
            {
                e.Cancel = true;
            }
        }

        private DialogResult PreClosingConfirmation()
        {
            DialogResult res = System.Windows.Forms.MessageBox.Show(" Do you want to quit?          ", "Quit...", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            return res;
        }

ハッピーコーディング

6
IMMORTAL

これは、CancelEventArgsがコード内のイベントハンドラーに渡されるオブジェクト参照であるためです。舞台裏のコードはFormClosingオブジェクトでCancelEventArgsを発生させ、すべてのイベントハンドラーは同じオブジェクトを受け取ります。すべてのハンドラーが順番を終えると、舞台裏のコードは送信されたCancelEventArgsオブジェクトをチェックして、そのCancelプロパティがtrueに設定されているかどうかを確認します。そうである場合、それは何もせず、イベントのFormCloseチェーンが停止します。 CancelfalseCancelEventArgsデフォルト値)の場合、つまりイベントのチェーンにCancelが設定されていない場合、バックグラウンドコードが続行されますに沿って、次にFormClosedイベントを発生させます。

詳細については、 MSDNのForm.FormClosingイベント を参照してください。

Formsでは、通常、すべての-ingイベントの後に-edイベントが続きます。 -ingイベントには通常CancelEventArgsがあり、Cancelプロパティをtrueに設定して、-edイベントの発生を停止できます。

3
j.i.h.