10

1 つのフォームでのみ発生するように見える非常に奇妙な動作があります。

基本的に私は のインスタンスを作成し、ノンブロッキングでフォームを表示するためFormに呼び出しています。Show()そのフォームのイベント ハンドラーには、特定の状況でLoad呼び出されるロジックがいくつかあります。this.Close()これはフォームを閉じますが、クライアント コードのフォームShow()メソッドはObjectDisposedException.

ObjectDisposedException からのスタック トレースは次のとおりです。

System.Windows.Forms.Control.CreateHandle()
で System.Windows.Forms.Form.CreateHandle()
で System.Windows.Forms.Control.get_Handle() で System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
で System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
で.Windows.Forms.Form.SetVisibleCore(Boolean value)
at System.Windows.Forms.Control.Show()
...など。

これは私が見ているものです:

  1. Control.Show()と呼ばれる
  2. 私のフォームが起動されました
  3. OnFormLoadメソッドが呼び出されます
  4. FormLoadイベントハンドラーが呼び出され、その中で呼び出しますthis.Close()
  5. OnFormClosingメソッドが呼び出されます
  6. FormClosingイベントハンドラが呼び出されます
  7. Dispose私のフォームとすべてのユーザーコントロールで呼び出されます

そして、Control.Show()メソッドの最後のどこかで、フォームへのハンドルを取得しようとしますが、オブジェクトが破棄されているとマークされているため、例外が発生して例外がスローされます。

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

何か案は?

4

13 に答える 13

34

そうするための最良の方法:

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

これは ObjectDisposedException を取得しない最も簡単な方法です

于 2013-07-22T08:49:57.493 に答える
8

これは古い問題であることは知っていますが、誰も明確な回答を投稿していないようです。

あなたはあなたが電話すると言い、Control.Show()それからForm.Close()フォームは破棄されます。まあ、MDI を使用するかShowDialog、文書化されているとおりに使用しない限り。ドキュメントの短いバージョンClose()は「フォームを閉じる」ですが、実際には特定の条件下で暗黙的に破棄します。

備考セクションを参照してください: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

もう一度フォームを表示したい場合。Hide()の代わりに メソッドを使用しClose()ます。

他の検索魂に役立つことを願っています。

そして皆さん、「時々うまくいく理由がわからない」で検索をやめないでください。それは、「念のため、このメソッドをもう一度呼び出す」という防御的なものがたくさんあるバグのあるソフトウェアになります。良くない。

于 2011-10-29T13:33:58.273 に答える
7

わかりました、私自身の質問に答えるのは嫌いですが、これは私を狂わせていました、そしてそれは私が今まで見た中で再現するのが最も難しいバグの1つでした。

私のフォームでは、OnFormLoadメソッドとOnFormCloseメソッドをオーバーライドしています。ここで、フォームのサイズ、場所、およびWindowStateをレジストリとの間で保存/復元します。このコードを取り出して、問題を修正しました。奇妙なことに、私はそれを元に戻しましたが、問題は再発しませんでした。

私はついに問題を再現しました。フォームを完全に開いて最大化し、次に閉じて、最大化された状態がレジストリに保存されるようにする必要があります。次に、もう一度開くと、最大化に設定され、ロードハンドラーで閉じると、閉じているときにサイズ/場所にアクセスしようとします。どうやらOnFormClosingメソッドでこれらの値にアクセスすると、フォームが破棄されたため、フォームが最大化された場合にのみ、フォームがフォーカスを試みます。これは違法です。

したがって、基本的に、フォームがLoadイベントからCloseを呼び出す場合、フォームのOnFormClosingメソッドでフォーム表示プロパティにアクセスすることはできません(最初にDisposedプロップをチェックしない限り)

私が知っているWinformsの知恵のかなり具体的な部分ですが、とにかくそれを書き留めています。

于 2009-04-08T19:35:08.900 に答える
3
protected override void CreateHandle()
   {
        base.CreateHandle();

        if (FormMustClose)  //FormMustClose is a variable in the loadevent.
        {
            Close();
        }
    }
于 2020-05-15T16:22:44.990 に答える
3

読み込みイベントでは、フォームを閉じるのはあまり良い考えではありません。Activated イベントの後に実行します。

于 2009-04-08T17:56:22.053 に答える
1

1 つの可能性:

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

これを行う前にフォームを見たことがあります...

于 2009-04-08T17:56:06.483 に答える
0

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

于 2012-02-11T18:57:57.963 に答える
0

わかりました、思ったよりも少し単純で一般的ですが、それでも奇妙でわかりにくいことがわかりました。

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

頭が痛い。

于 2009-04-08T20:08:19.333 に答える
0

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

そうは言っても、なぜそれが機能する場合と機能しない場合があるのか​​ わかりません。

于 2009-04-08T17:55:48.013 に答える