0

今日、私は自分のコードに、少し前に処理されたと思っていたバグに気づきました。私はWindows Formsアプリケーションに取り組んでおり、form_loadイベントを頻繁に使用しています。イベントで問題が発生し、例外がスローされた場合の状況を処理するにForm_loadは、次のコードを使用します。

catch (Exception ex)
{
    LogErrorAndShowMessage(ex, Resources.ERROR_LOAD);

    //Otherwise Error : "Cannot call Close() while doing CreateHandle()".
    this.BeginInvoke(new InvokeDelegate(CloseTheForm));
    LoadForm<Materials>(closeAlreadyOpened : false);
}

そして、これは私がデリゲートとメソッドを宣言する方法です:

public delegate void InvokeDelegate();//used if form load fails
private void CloseTheForm()
{
    this.Close();
}

今日からうまくいきました。何が起こったのか-コンボボックスForm_loadにを設定した場合、メソッドからエラーがスローされ、使用前とまったく同じエラーが発生しました- 。DataSourceSetDataSourceBeginInvokeCannot call Close() while doing CreateHandle()

これは例外的な動作です。例外が他の場所からスローされた場合、コードは引き続き正常に機能します。データソースの設定中にエラーが発生した場合のみです。

この例外的な動作を引き起こす可能性のある提案と、それを修正するにはどうすればよいですか?

PS

これが私が新しいフォームを作成する方法です:

protected void LoadForm<T>(ToolStripButton/*ToolStripDropDownButton*/ formButton, 
                           string buttonText, 
                           long? loadEntityId = null, 
                           bool closeAlreadyOpened = true) where T : BaseForm
{
    MainForm parentFrm = GetParentForm();

    if (parentFrm != null)
    {
        if (formButton != null)
        {
            parentFrm.SetForeColor(formButton);
        }

        T openForm = SingletonFormProvider.GetInstance<T>(parentFrm, 
                                                          closeAlreadyOpened);
        openForm.LoadEntityId = loadEntityId;
        openForm.MdiParent = parentFrm;
        openForm.Dock = DockStyle.Fill;
        openForm.Show();
        openForm.Activate();
    }
    else
    {
        MessageBox.Show("Parent form not found!", "Error", 
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

多分提供されたように私はこの問題に対処するために周りにHans Passant置くべきですか?try-catchopenForm.Show()

4

1 に答える 1

5

Loadイベントはこのように厄介です。通常、フォームのShow()メソッドが呼び出されたときに発生します。ただし、フォームコンストラクターの初期化コードでネイティブウィンドウの作成が必要な場合は、早期にトリガーされる可能性があります。フォームオブジェクトはまだ完全に初期化されていないため、かなり不健全です。Loadイベントハンドラーにブレークポイントを設定し、デバッガーの[コールスタック]ウィンドウを確認することで、どのコードがそれを実行したかをいつでも確認できます。

一般に、Loadイベントは回避する必要があります。これは、ウィンドウの実際のサイズを知る必要があるまれな場合にのみ必要です。他のすべては、通常の.NETクラスの場合と同様に、コンストラクターに属します。例外をキャッチしてログに記録するために何かをする必要があります。これは、クラスファクトリで行うのが最適です。ボイラープレートファクトリは次のようになります。

    public static Form1 CreateInstance() {
        try {
            var frm = new Form1();
            frm.Show();
            return frm;
        }
        catch (Exception ex) {
            LogErrorAndShowMessage(ex);
            return null;
        }
    }
于 2013-03-26T17:50:55.347 に答える