2009-04-08 51 views
7

私は非常に奇妙な動作を1つのフォームで発生するようです。Loadハンドラからフォームを閉じる

基本的に私はFormのインスタンスを作成していて、Show()を呼び出してフォームをノンブロッキングで表示しています。そのフォームのLoadイベントハンドラでは、特定の状況下でthis.Close()を呼び出すロジックがあります。これによりフォームが閉じられますが、クライアントコード内のフォームShow()ObjectDisposedExceptionをスローします。システムでSystem.Windows.Forms.Form.CreateHandleでSystem.Windows.Forms.Control.CreateHandleで

()
()

次のように説明ObjectDisposedExceptionからスタックトレースがあります.Windows.Forms.Control.get_Handle()System.Windows.Forms.Controlで
System.Windows.Forms.ContainerControl.FocusActiveControlInternal()System.Windows.Forms.Form.SetVisibleCoreで
(ブール値)で
.Show()
...など。これは私が見ているものです

起こる:

  1. Control.Show()が私のフォームが起動される
  2. と呼ばれる
  3. 内部、FormLoadイベントハンドラが呼び出され
  4. と呼ばれる​​方法そのうち私はthis.Close()
  5. OnFormClosingの方法はcaですlled
  6. Dispose
  7. が私のフォームで呼び出されると、すべてのそれはだユーザーは

制御し、その後、どこかControl.Show()方法の終わりに向かって、それはフォームへのハンドルを取得しようとすると呼ばれるFormClosingイベントハンドラオブジェクトは破棄されてマークされているため、例外をスローします。

私の本当の疑問は、なぜ私は例外なく、私が持っている他のすべてのフォームで同じことをすることができますか?それはGCの問題ですか?私はthis.Close()の直後にGC.Collect()コールを入れようとしましたが、違いはありません。私が言ったように、それはフォームの変数の範囲など、子のユーザーコントロールに関係なく、このフォーム上の時間の100%、他の場所では決して発生します。

アイデア?

答えて

7

これは古い問題ですが、誰もobvoiusの回答を投稿していないようです。

あなたはControl.Show()と電話し、次にForm.Close()と呼んでから、そのフォームをDisposedにします。まあ、MDIを使用しないか、または文書化されている通りのShowDialogを使用しない限り。しかし、Close()のドキュメントの短いバージョンは「フォームを閉じます」となっていますが、実際には特定の条件の下で暗黙的にもそれを処理します。あなたがもう一度フォームを表示したい場合は http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

は備考を参照してください。 Close()の代わりにHide()メソッドを使用します。

希望は他の検索魂に役立ちます。

皆さん、「私はなぜ時には動作するのかわかりません」で検索を停止しないでください。それはたくさんの守備的な "私はこのメソッドをちょうどの場合に呼ぶ"というバグの多いソフトウェアになります。良くない。

+0

残念ながら私はWindowsの開発者をもうやらないが、これは正しいと思う。ありがとう! – LoveMeSomeCode

+0

.Net2.0で動作しません – Vadim

0

あなたが望むものを達成するためにクリーンな方法はFormからカスタムフォームクラスの導出を作るためにも、そしてあなたの状態をチェックし、キャンセルするOnFormLoad(...)および/またはShow()をオーバーライドするかもしれないと、それをよく見ずに、私には思えます早い段階で。

私はそれが時々、そして他の時にはうまくいかないと言いました。

+0

実際にはそうです。私はそれを言及していない/すべて私のフォームのcはそうです。基本フォームはOnFormLoadとOnFormCloseをオーバーライドしますが、これらのメソッドではレジストリの処理だけを行います。呼び出し順序はすべての形式で同じです。 – LoveMeSomeCode

1

一つの可能​​性:

彼らはFormLoadイベントで初期化して有効にされているこのフォーム、上のタイマーを有することができます。タイマーが起動時にフォームにアクセスしようとすると、フォームが閉じられる前に、タイマーを無効にして停止する必要があります。 Loadイベントでそれがこれを行う前に、私は、フォームを見てきました

...

+0

良い考えですが、このフォームにタイマーはありません。いくつかのユーザーコントロールが、私はすべての彼らのDisposeメソッドが呼び出されていることを確認するためにチェックした。 – LoveMeSomeCode

3

は本当に良いアイデアは、フォームを閉じないです。 Activatedイベントの後に実行します。

0

例外が発生したときに、どのコード行が呼び出されているかを確認するために、.netコードにステップインしてみましたか? VS 2008をお持ちの場合は、[ツール] - > [オプション] - > [デバッグ]を選択し、[.NET Frameworkソースステップを有効にする]を選択します。これは、必要なファイルをすべてダウンロードするにはしばらく時間がかかることがありますが、このようにしてform.Show()に入り、何が起こっているのかを正確に確認することができます。

+0

いいえ、私は願っています。私はVS 2005を使用しています。私はリフレクターをチェックしましたが、コールスタックのように:コントロールの最後の近くにあります。それが破棄された場合、例外をスローするハンドルゲッターを呼び出すFocusActiveControlInternalを呼び出します。 – LoveMeSomeCode

5

[OK]を自分自身の質問に答えることは嫌いだが、これはナッツを運転していた、それは私が今まで見た中で最も難しいバグの一つでした。

私のフォームでは、フォームのサイズ、場所、WindowStateをレジストリに/から復元するOnFormLoadメソッドとOnFormCloseメソッドをオーバーライドしています。私はこのコードを取り出し、問題を修正しました。奇妙なことは、私はそれを取り戻し、問題は戻ってこないということです。

私は最後に問題を再現しました:最大化状態がレジストリに保存されるように、フォームを完全に開いて最大化してから閉じる必要があります。それを再び開くと、Maximizedに設定され、Loadハンドラで閉じられると、閉じているときにSize/Locationにアクセスしようとします。明らかにOnFormClosingメソッドでこれらの値にアクセスすると、フォームが処理されているため、フォームが最大化されている場合にのみ、フォームにはフォーカスが掛かります。そのフォームが閉じるそれから呼び出すことが起こっている場合は、フォームのOnFormClosing方法でフォームの表示プロパティにアクセスすることはできませんので、基本的に

は、Loadイベントです。(あなたが配置されているのを確認しない限り、最初の小道具)かなり

とにかく私はそれを書いています。

0

私が思っていたよりも少しシンプルで一般的ですが、それでもなお奇妙で不明瞭です。

フォームがロード/クローズされるときにサイズ/位置/ WindowStateのフォームを保存/ロードする場合は、Form Loadイベントハンドラが起動するようにOnLoadメソッドがbase.OnLoadを最初に呼び出すようにする必要がありますTHENがプロパティを設定します。そうしないと、フォームがLoadメソッドの内部からCloseを呼び出す場合にのみ問題が発生します。フォームの終了イベントが完了した後、Show呼び出しでObjectDisposedExceptionが発生します。

頭が痛いです。

0

Form.Shown()もトリックです。

22

そうする最良の方法は:

this.BeginInvoke(new MethodInvoker(this.Close)); 

これは、ユーザーが右上にクロスを押したかのようにフォームを閉じるようにしたい場合は、文句を言わない説明ObjectDisposedException

+1

.Net2.0でうまく動作します – Vadim

3

を取得する最も簡単な方法ですコーナー(通常はキャンセルを意味します)では、次のコードを追加してください。

this.DialogResult = System.Windows.Forms.DialogResult.Cancel; 
this.Close(); 

これは、フォームのロード機能で動作します。

private void MyForm_Load (object sender, EventArgs e) 
{ 
    // do some initializations 

    if (!ContinueLoadingForm()) 
    { 
     this.DialogResult = System.Windows.Forms.DialogResult.Cancel; 
     this.Close(); 
     return; 
    } 
    // continue loading the form 
} 

フォームは、しばらくの間表示されるようにしたくない場合は、デザイナー、例えば(Visibleプロパティをfalseを設定またはコンストラクタ)を読み込み、プログラムが読み込みを続けることができると確信したときにtrueに戻します。

+0

ただし、フォームが表示されることはありません。 –

0

私が理解しているように、フォームのDialogResultを設定すると、フォームが閉じられます。これはDialogResult.None以外である必要があります。 (つまり、Form.Close()メソッドを呼び出す必要はありません)。

問題は、コード内の他の場所で、フォームまたはフォーム内のコントロールのプロパティにアクセスしているため、フォームが閉じられないことがあります。

また、提案されているように、あなたがプロパティを持っている場合には、最適な場合もあります。

private bool _loadedOk = false; 

あなたの初期化コードで設定したフォームにします。 Form_Loadedの後のイベントの1つでは、これを調べて、フォームが偽であればフォームを閉じます。

おそらく、誰かがこれを行うには最高のイベントを提案できますか?

関連する問題