6

FormClosingに基づいてイベントを異なる方法で処理するフォームがありCloseReasonます。たとえばCloseReason.UserClosing、WCFサービス呼び出しから特定の値が返されたときにプログラムでイベントを呼び出しApplication.Exit()、通知アイコンのコンテキストメニューItemClickedイベントから呼び出して、他の条件の中でも特にアプリを閉じるときに、フォームを最小化します。

私のアプリはこれまで期待どおりに機能し、呼び出されFormClosingたときに常にイベントを発生Application.Exit()させていましたが、いくつかの変更を加えた後はそのように動作しません。ほとんどの場合、アプリはイベントを発生させずに閉じており、発生している場合は、フォームを終了せずにイベントのコードが実行されます(データベース作業、アイコンの破棄を通知)。

これはどのように起こりますか?

4

2 に答える 2

14

はい、これは可能です。Application.Exit()メソッドは、Application.OpenFormsコレクション内のフォームを反復処理して、OnFormClosing()メソッドを呼び出します。Winformsにはバグがあり、そのコレクションは開いているフォームを追跡できなくなります。このコードはそれを示しています:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }
    protected override void OnHandleCreated(EventArgs e) {
        // Set breakpoint here:
        base.OnHandleCreated(e);
    }
    protected override void OnMouseDown(MouseEventArgs e) {
        this.ShowInTaskbar = !this.ShowInTaskbar;
        MessageBox.Show(string.Format("There are {0} open forms", Application.OpenForms.Count));
        Application.Exit();
    }
    protected override void OnFormClosing(FormClosingEventArgs e) {
        MessageBox.Show("you won't see this");
        base.OnFormClosing(e);
    }
}

フォームをクリックしてバグをトリガーします。0の開いているフォームがどのように報告され、OnFormClosingにメッセージボックスが表示されなかったかに注意してください。

それを引き起こすのは、ShowInTaskbarプロパティへの割り当てです。そのようなプロパティはいくつかありますが、NotifyIconがある場合に使用する可能性が高いため、ShowInTaskbarを選択しました。RightToLeftはもう1つです。これらのプロパティは、ウィンドウがネイティブのCreateWindowEx()API関数で作成された場合にのみ指定できるため、特別です。それらを変更するには、Winformsがかなり英雄的なことをする必要があります。ウィンドウを破壊して再作成します。残念ながら、これもバグの引き金となります。ウィンドウを破棄すると、OpenFormsコレクションからフォームが削除され、追加し直すのを忘れてしまいます。

このスニペットからOnHandleCreated()メソッドをコピーしてフォームに貼り付け、ブレークポイントを設定します。ウィンドウが最初に作成されたときに、一度トリガーする必要があります。再度トリガーされてバグシナリオが呼び出されると、呼び出しスタックを調べて、クラス内のどのコードがトリガーしたかを確認できます。そのコードを無効にして、別の方法を見つける必要があります。コンストラクターでShowInTaskbarプロパティを設定することは問題ありませんが、Loadイベントハンドラーのように、ウィンドウの作成後に割り当てた場合にのみ問題が発生します。

于 2012-11-23T10:35:10.860 に答える
1

ここで述べたように

アプリケーションを終了するためにApplication.Exitメソッドが呼び出された場合、Form.ClosedイベントとForm.Closingイベントは発生しません。これらのイベントのいずれかに実行する必要のある検証コードがある場合は、Exitメソッドを呼び出す前に、開いているフォームごとに個別にForm.Closeメソッドを呼び出す必要があります。

編集

を使用しているので、その場合は、終了をキャンセルしたフォームを判別し、問題をさらに調査するのに役立つ可能性FormClosingのあるオーバーロードを使用してみてください。Exit

于 2012-11-23T09:58:37.907 に答える