C # -Kompilierfehler: "Invoke oder BeginInvoke kann nicht für ein Steuerelement aufgerufen werden, bis das Fensterhandle erstellt wurde."

8

Ich habe gerade eine Frage dazu gestellt, wie man einen Delegaten dazu bringt, ein Textfeld in einem anderen Formular zu aktualisieren. Gerade als ich dachte, ich hätte die Antwort mit Invoke ... das passiert. Hier ist mein Code:

Hauptformularcode:

%Vor%

Protokollierungsklassencode:

%Vor%
  • Kompilierungsfehler:

    InvalidOperationException war unbehandelt - Invoke oder BeginInvoke kann bis zu einer Kontrolle nicht aufgerufen werden Der Fensterhandle wurde erstellt.

Ich habe bereits versucht, ein Handle für das Log-Element zu erstellen ... aber das hat nicht funktioniert. Das Problem ist, ich habe keinen Hinweis was ich tue und ich habe Google extensiv durchsucht, nur um vage Antworten zu finden.

Bitte sagen Sie mir, wie ich das Handle erstellen soll, bevor ich diesen Delegaten aufruft. Wenn Sie schon dabei sind, geben Sie mir einige Möglichkeiten, wie ich diesen Code einfacher machen kann. Zum Beispiel möchte ich nicht zwei Add-Funktionen ... Ich musste das tun, weil es für mich keine Möglichkeit gab, ein Element zu finden, aus der Logging-Klasse aufzurufen. Gibt es einen besseren Weg, um das zu erreichen, was ich tun muss?

Danke !!!

BEARBEITEN:

Mein Projekt ist ziemlich groß, aber das sind die einzigen Elemente, die dieses spezielle Problem verursachen.

Log ist meine RichTextBox1 (Log.Items.Add (message)) Ich habe sie in Log umbenannt, damit sie einfacher zu tippen ist.

Ich rufe updateLog (Nachricht) von einem anderen Formular obwohl ... lassen Sie mich das hier aktualisieren (obwohl es keinen Unterschied macht, wo ich updateLog (Nachricht) von ihm rufe, gibt mir immer noch diesen Fehler)

Ihr müsst die Dinge für mich einfacher machen ... und Beispiele liefern. Ich verstehe die HÄLFTE von allem, was ihr hier sagt, nicht. Ich habe keine Ahnung, wie ich mit dem Aufruf von Methoden und Handles arbeiten soll. Ich habe den Mist auch daraus recherchiert ...

ZWEITE BEARBEITUNG:

Ich glaube, ich habe das Problem lokalisiert, weiß aber nicht, wie ich es beheben kann.

In meiner Protokollierungsklasse verwende ich diesen Code, um mainClass zu erstellen:

statisch Haupt mainClass = new Main ();

Ich erstelle ein völlig neues Blueprint-Replikat für Main (), einschließlich Log (die richtextbox, die ich zu aktualisieren versuche)

Wenn ich updateLog (Nachricht) anrufe, versuche ich, das Log (richtextbox) auf der zweiten Entität von Main () zu aktualisieren, die sonst als mainClass bezeichnet wird. Natürlich werde ich diese Ausnahme auslösen, weil ich das Replikat des aktuellen Main nicht einmal gesehen habe.

Dafür schieße ich, dank einer Person, die eine Antwort gegeben hat:

%Vor%

Ich muss mainClass nicht mit dem new () -Operator erstellen, weil ich keinen neuen Blueprint des Formulars erstellen möchte, um das aktuelle Formular bearbeiten zu können.

Der obige Code funktioniert nicht, ich kann nicht einmal die Anwendung finden. Ist das überhaupt C # -Syntax?

Wenn ich erreichen kann, dass der obige Code funktioniert, denke ich, dass ich mein Problem lösen und dieses Problem nach einigen Stunden der Suche nach Antworten endlich ausräumen kann.

ENDBEARBEITUNG:

Ich habe es herausgefunden, dank einem der Benutzer unten. Hier ist mein aktualisierter Code:

Hauptformularcode:

%Vor%

Protokollierungsklassencode:

%Vor%     
OneShot 04.02.2009, 20:24
quelle

9 Antworten

12

Richtig, ich fange wieder an.

Um zu verstehen, was passiert, müssen Sie verstehen, wie sich .NET und Windows aufeinander beziehen. .NET läuft unter Windows und umschließt viele der nativen Win32-Konzepte wie ein Fenster, eine Listenansicht, ein Bearbeitungsfeld (der Win32-Name für ein Standard-Textfeld). Dies bedeutet, dass Sie eine gültige .NET-Instanz einer TextBox oder eines Formulars haben können, aber noch nicht die zugrunde liegende Windows-Version dieses Elements (EditBox oder Window) haben. Wenn HandleCreated true ist, wird die Windows-Version des Elements erstellt.

Ihr Problem tritt auf, weil etwas dazu führt, dass die Methode logAdd aufgerufen wird, bevor das Fenster des Formulars erstellt wurde. Dies bedeutet, dass irgendwo während Ihres Starts, nachdem die Form-Instanz instanziiert wurde, aber bevor das Fenster-Handle erstellt wurde, versucht wird, logAdd aufzurufen. Wenn Sie einen Haltepunkt zu logAdd hinzufügen, sollten Sie sehen können, was diesen Aufruf ausführt. Was Sie finden, ist, dass der Aufruf an der Main-Instanz erfolgt, die Sie in Ihrer Logger-Klasse erstellen, und NICHT an der Main-Instanz, die tatsächlich ausgeführt wird. Da die Logger-Instanz niemals angezeigt wird, wird das Fenster-Handle nicht erstellt, und Sie erhalten Ihren Fehler.

Die allgemeine Art, wie eine Anwendung ausgeführt wird, besteht darin, Application.Run (new Main ()) in Ihrer Startmethode aufzurufen, die sich normalerweise in der Program-Klasse befindet und Main genannt wird. Sie müssen Ihren Logger auf diese Instanz von main verweisen.

Es gibt mehrere Möglichkeiten, die Instanz des Formulars mit jeweils eigenen Vorbehalten abzurufen. Aus Gründen der Einfachheit können Sie die Instanz jedoch von der Hauptklasse selbst ausschließen. Zum Beispiel:

%Vor%     
Jeff Yates 04.02.2009, 21:53
quelle
12

Ich habe dies in der Vergangenheit mit der folgenden Methode gelöst:

%Vor%

Rufen Sie invokeOnFormThread anstelle von Invoke auf. Es wird nur den Thread des Formulars verwenden, wenn bereits ein Handle erstellt wurde, andernfalls wird der Thread des Aufrufers verwendet.

    
Michael Meadows 04.02.2009 20:47
quelle
2

Wenn Sie diesen Fehler erhalten, bedeutet dies fast immer, dass Sie versucht haben, auf ein Steuerelement oder ein Formular zu reagieren, bevor es tatsächlich erstellt wurde.

In WinForms haben GUI-Elemente zwei semi-unabhängige Leben: als Klassen im Speicher und als Entitäten im Betriebssystem. Daher ist es möglich, auf ein Steuerelement in .net zu verweisen, das noch nicht erstellt wurde. Das "Handle, das erstellt wird" bezieht sich auf eine Nummer, die dem Steuerelement vom Betriebssystem zugewiesen wird, damit Programme seine Eigenschaften ändern können.

In diesem Fall können die meisten Fehler behoben werden, indem ein Flag am Ende des Ladeereignisses des Formulars gesetzt wird und nur versucht wird, die Steuerelemente des Formulars zu manipulieren, nachdem dieses Flag gesetzt wurde.

    
Yes - that Jake. 04.02.2009 20:30
quelle
2

Es ist ein Laufzeitfehler, kein Compilerfehler.

Ihr Formular, "Main", muss angezeigt werden (daher ein Fensterhandle erstellt), bevor Sie Aufrufe von BeginInvoke oder Invoke darauf tätigen können.

In solchen Situationen überlasse ich normalerweise das Formular, um festzustellen, ob ein Aufruf von BeginInvoke oder Invoke erforderlich ist. Sie können das mit einem Aufruf von InvokeRequired testen (MSDN überprüfen).

Für den Anfang würde ich den Aufruf logAddDelegate in der updateLog-Methode der Loggin-Klasse loswerden. Rufen Sie einfach das Formular auf, um ein Protokoll hinzuzufügen. Wie so:

%Vor%

}

Sie können also sehen, dass das Formular selbst dafür zuständig ist, festzustellen, ob es die Methode asynchron aufrufen muss oder nicht.

Dies wird jedoch Ihren Laufzeitfehler immer noch nicht beheben, da Sie das Formular aufrufen, bevor es angezeigt wird. Sie können überprüfen, ob das Handle des Formulars null ist oder nicht. Dadurch können Sie zumindest überprüfen, ob Sie mit einem gültigen Formular arbeiten.

    
Chris Holmes 04.02.2009 21:07
quelle
1

Dieser Fehler tritt häufig auf, wenn Sie ein Fenster aufrufen, das noch nicht "angezeigt" wurde. Sind Sie sicher, dass Sie keine zweite Instanz der Hauptklasse mit Ihrem Code in der Protokollierungsklasse (speziell der ersten Zeile) erstellen? Es kann sein, dass das Hauptformular, das Sie anrufen, nicht das Hauptformular ist, das Sie betrachten. Wenn Sie das überprüfen möchten, fügen Sie einen Aufruf von "MainClass.Show ()" nur innerhalb Ihres Protokollierungsaufrufs hinzu. Wenn Sie eine zweite Kopie des Hauptformulars erhalten, erscheint das Problem, dass Ihre Protokollierungsklasse nicht auf die richtige 'Instanz' Ihres Formulars verweist.

Denken Sie an die Klasse als "Blaupause". Jede Instanz der Klasse (erstellt mit dem Wort "neu") ist ein anderes Objekt, das aus dem Entwurf erstellt wurde. Nur weil zwei Objekte (in diesem Fall Ihre beiden Hauptformen) denselben Bauplan haben, bedeutet das nicht, dass Sie sie austauschbar verwenden können. In diesem Fall haben Sie bereits ein Hauptformular und möchten es "wiederverwenden". Sie können versuchen:

%Vor%

in Ihrer Log-Funktion anstelle dessen, was Sie gerade haben. Der Unterschied besteht darin, dass der Aufruf von Application.OpenForms.OfType () als erstes in Ihre Anwendung geht und das ACTUAL-Hauptformular, das Sie gerade sehen, abruft (technisch wird es die erste Instanz davon abrufen) und Ihren Aufruf darauf ausführen Form, direkt.

Hoffe, das hilft.

    
GWLlosa 04.02.2009 21:13
quelle
1

Dies soll helfen, falls eine andere Person damit fertig wird. Mein Problem: VB.net: "Invoke oder BeginInvoke kann nicht auf einem Steuerelement aufgerufen werden, bis das Fensterhandle erstellt wurde." Ich habe ein Formular geschlossen, das über einen Handler für das Ereignis verfügt, um den Delegaten zu aktualisieren, ohne den Handler für das Ereignis zu entfernen.

Was ich getan habe: Als ich das Formular geschlossen habe, habe ich alle Handler entfernt und sie zugewiesen, als ich das Formular geöffnet habe. Es löste das Problem.

    
Lucy 02.03.2011 15:27
quelle
0
  

logAddDelegate (Nachricht);

Ich denke, Sie rufen dies auf, bevor das Form_Load-Ereignis ausgelöst wurde. Korrigieren Sie Ihren Code, um darauf zu warten, dass das Formular vor dem Aufrufen von logAddDelegate (...) geladen wird, d. H. Vor dem Aufrufen von Logging.updateLog ()

    
Sandeep Datta 04.02.2009 20:35
quelle
0

Ist das Ihr genauer Code? Sie rufen this.Log.Items.Add(message); in Ihrer add (string) -Methode auf, aber Ihre Protokollierungsklasse heißt Logging, nicht Log. Hast du ein anderes Formular namens Log vielleicht? Wenn dieses Formular beim Aufruf der Methode add nicht erstellt wurde, erhalten Sie diese Ausnahme.

    
Jamie Penney 04.02.2009 20:51
quelle
0

Ich fand das InvokeRequired nicht zuverlässig, also benutze ich einfach

%Vor%     
Mathieu 15.06.2012 05:56
quelle