Schließen eines Formulars vom Load-Handler

7

Ich habe ein sehr merkwürdiges Verhalten, das nur auf einer Form vorkommt.

Grundsätzlich erstelle ich eine Instanz von Form und rufe Show() auf, um das nicht blockierende Formular anzuzeigen. In der Ereignisbehandlungsroutine Load des Formulars habe ich eine Logik, die unter bestimmten Umständen this.Close() aufrufen kann. Dadurch wird das Formular geschlossen, aber die Methode Show() im Clientcode gibt ObjectDisposedException aus.

Der Stack-Trace von der ObjectDisposedException ist wie folgt:

  

bei System.Windows.Forms.Control.CreateHandle ()
    bei System.Windows.Forms.Form.CreateHandle ()
    bei System.Windows.Forms.Control.get_Handle ()
    bei System.Windows.Forms.ContainerControl.FocusActiveControlInternal ()
    bei System.Windows.Forms.Form.SetVisibleCore (boolescher Wert)
    bei System.Windows.Forms.Control.Show ()
   ... usw.

Dies ist was ich sehe passieren:

  1. Control.Show() heißt
  2. mein Formular wird gestartet
  3. Die Methode OnFormLoad heißt
  4. Der FormLoad Event-Handler wird aufgerufen, innerhalb dessen ich this.Close() aufruft
  5. Die Methode OnFormClosing heißt
  6. Der Ereignishandler FormClosing wird
  7. aufgerufen
  8. Dispose wird auf meinem Formular und allen Benutzersteuerelementen
  9. aufgerufen

und dann irgendwo gegen Ende der Control.Show() -Methode, versucht es, ein Handle zu dem Formular zu bekommen, das ausflippt und eine Ausnahme auslöst, weil das Objekt als dispose markiert ist.

Meine eigentliche Frage ist, warum kann ich genau dasselbe auf jeder anderen Form machen, die ich ohne Ausnahmen habe? Ist es ein GC-Problem? Ich habe versucht, einen GC.Collect() Aufruf direkt nach dem this.Close() zu setzen und es macht keinen Unterschied. Wie ich schon sagte, passiert es 100% der Zeit in diesem Formular und nirgendwo sonst, unabhängig von den untergeordneten Benutzersteuerelementen, dem Gültigkeitsbereich der Formularvariablen usw.

Irgendwelche Ideen?

    
LoveMeSomeCode 08.04.2009, 17:51
quelle

11 Antworten

8

Ich weiß, dass dies ein altes Problem ist, aber niemand schien die obvoius Antwort veröffentlicht zu haben.

Sie sagen, dass Sie Control.Show() und dann Form.Close() aufrufen und dann das Formular Disposed of ist. Nun, es sei denn, Sie verwenden MDI oder ShowDialog , das ist genauso dokumentiert. Die Kurzversion der Close() -Dokumentation lautet zwar "Schließt das Formular", es wird aber unter bestimmten Bedingungen auch implizit disponiert.

Siehe Abschnitt Anmerkungen: Ссылка

Wenn Sie ein Formular erneut anzeigen möchten. Verwenden Sie die Methode Hide() anstelle von Close() .

Hoffe das hilft anderen suchenden Seelen.

Und Leute, hören Sie nicht auf zu suchen "Ich weiß nicht, warum es manchmal funktioniert". Das wird buggy Software mit viel Defensive "Ich werde diese Methode wieder nur für den Fall" nennen. Nicht gut.

    
JonasW 29.10.2011, 13:33
quelle
22

Der beste Weg dazu:

%Vor%

Dies ist die einfachste Methode, mit der Sie ObjectDisposedException

nicht erhalten     
RcMan 22.07.2013 08:49
quelle
5

Ok, hasse es, meine eigene Frage zu beantworten, aber das hat mich verrückt gemacht, und es war einer der schwierigsten Fehler, den ich je gesehen habe.

In meinem Formular überschreibe ich die Methoden OnFormLoad und OnFormClose, in denen ich die Größe, den Standort und den WindowState des Formulars in der Registrierung speichern / wiederherstellen kann. Ich habe diesen Code herausgenommen und das Problem behoben. Das Seltsame ist, ich habe es zurückgestellt und das Problem ist nicht zurückgekommen.

Ich habe das Problem schließlich reproduziert: Sie müssen das Formular vollständig öffnen, maximieren und dann schließen, damit der Maximized-Status in der Registrierung gespeichert wird. Wenn Sie es dann erneut öffnen, wird es auf Maximiert gesetzt, und wenn es im Load-Handler geschlossen wird, versucht es, auf die Größe / Position zuzugreifen, während es geschlossen wird. Scheint der Zugriff auf diese Werte in der OnFormClosing-Methode das Formular versucht, IF und ONLY zu konzentrieren, wenn das Formular maximiert ist, was illegal ist, da das Formular entsorgt wurde.

Sie können also nicht auf Formularanzeigeeigenschaften in der OnFormClosing-Methode eines Formulars zugreifen, wenn dieses Formular vom Load-Ereignis aus Schließen aufruft (sofern Sie nicht zuerst die Disposed-Property überprüft haben)

ziemlich genaues Stück Winforms Weisheit, die ich kenne, aber ich schreibe es trotzdem auf.

    
LoveMeSomeCode 08.04.2009 19:35
quelle
3

In load event ist nicht wirklich gut Idee schließen Sie das Formular. Tun Sie es nach dem Activated-Ereignis.

    
TcKs 08.04.2009 17:56
quelle
3

Wenn Sie ein Formular so schließen möchten, als hätte der Benutzer das Kreuz in der oberen rechten Ecke gedrückt (normalerweise bedeutet das Abbrechen), fügen Sie einfach den folgenden Code hinzu.

%Vor%

Dies funktioniert auch in der Formularladefunktion:

%Vor%

Wenn das Formular für eine kurze Zeit nicht sichtbar sein soll, setzen Sie die Visible-Eigenschaft auf false (z. B. im Designer oder Konstruktor) und setzen Sie es auf true zurück, wenn Sie sicher sind, dass das Programm weiter geladen werden kann.

    
Harald Coppoolse 30.10.2013 09:25
quelle
1

Eine Möglichkeit:

Sie verfügen möglicherweise über einen Zeitgeber für dieses Formular, das in ihrem FormLoad-Ereignis initialisiert und aktiviert wird. Der Timer müsste auch deaktiviert und gestoppt werden, bevor das Formular geschlossen wurde, wenn der Timer versucht, auf das Formular zuzugreifen, wenn es ausgelöst wird.

Ich habe schon Formen gesehen, die das machen ...

    
Reed Copsey 08.04.2009 17:56
quelle
0

Es scheint mir, ohne genau darauf zu achten, dass der sauberste Weg, um das zu erreichen, was Sie wollen, darin besteht, eine benutzerdefinierte Formklasse von Form zu erstellen und OnFormLoad(...) und / oder Show() zu überschreiben für Ihren Zustand und früh aufheben.

Das heißt, ich weiß nicht, warum es manchmal und nicht zu anderen Zeiten funktionieren würde.

    
mquander 08.04.2009 17:55
quelle
0

Haben Sie versucht, in den .net-Code zu gehen, um zu sehen, welche Codezeile aufgerufen wird, wenn die Ausnahme auftritt? Wenn Sie VS 2008 haben, können Sie dies tun, indem Sie zu Extras - & gt; Optionen - & gt; Debuggen und wählen Sie Enable .NET Framework Source Stepping. Seien Sie gewarnt, dies kann eine Weile dauern, um alle notwendigen Dateien herunterzuladen, aber auf diese Weise können Sie in die Form.Show () treten und genau sehen, was vor sich geht.

    
Ross Goddard 08.04.2009 18:10
quelle
0

Ok, es stellt sich heraus, dass es etwas einfacher und generischer ist, als ich dachte, aber immer noch komisch und unklar.

Wenn Sie das Formular Size / Location / WindowState beim Laden / Schließen des Formulars speichern / laden, müssen Sie sicherstellen, dass die OnLoad-Methode zuerst base.OnLoad aufruft, damit der Form Load Event-Handler ausgelöst wird. und DANN legen Sie die Eigenschaften fest. Wenn Sie dies nicht tun, wird nur ein Problem verursacht, wenn das Formular innerhalb der Load-Methode Close aufruft. Nach dem Schließen des Formulars erhalten Sie eine ObjectDisposedException für den Show-Aufruf.

Mein Kopf tut weh.

    
LoveMeSomeCode 08.04.2009 20:08
quelle
0

Form.Shown () Ist der Trick auch.

    
Vahid Ghadiri 11.02.2012 18:57
quelle
0

Wie ich es verstehe, wird durch das Setzen des DialogResult des Formulars das Formular geschlossen - möglicherweise muss es anders als DialogResult.None sein. (Sie müssen dann die Form.Close () -Methode nicht aufrufen.)

Das Problem liegt auch darin, dass Sie, wenn Sie anderswo im Code auf eine Eigenschaft des Formulars oder des Steuerelements zugreifen, die das Schließen des Formulars verhindern kann.

Es kann auch am besten sein, wenn Sie, wie vorgeschlagen, eine Eigenschaft haben, z.B.

%Vor%

in Ihrem Formular, das Sie in Ihrem Initialisierungscode festgelegt haben. In einem der späteren Ereignisse nach Form_Loaded befragen Sie dies dann und schließen das Formular, wenn es falsch ist.

Vielleicht kann jemand das beste Ereignis vorschlagen, um dies in ??

zu tun     
mattpm 18.11.2015 23:44
quelle