C # Compiler-Fehler: „Invoke oder BeginInvoke kann nicht auf einem Steuerelement aufgerufen werden, bis das Fenster-Handle erstellt wurde.“

StackOverflow https://stackoverflow.com/questions/513131

Frage

Ich habe gerade gebucht eine Frage, wie einen Delegierten erhält eine Textbox auf einem anderes Formular zu aktualisieren. Gerade als ich dachte, dass ich die Antwort mit Invoke hatte ... dies geschieht. Hier ist mein Code:

Hauptformular Code:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {   /////////////////////////// COMPILER ERROR BELOW ///////////
            this.Invoke(new logAdd(add), new object[] { message }); // Compile error occurs here     
        }////////////////////////////// COMPILER ERROR ABOVE ///////////

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            string message = "Here my message is"; // changed this
            ErrorLogging.updateLog(message);  // changed this
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

Protokollierung Klassencode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {
        static Main mainClass = new Main();
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
  • Übersetzen Fehler:

    InvalidOperationException war unhandled - Invoke oder BeginInvoke kann nicht auf einem Steuerelement aufgerufen werden, bis das Fensterhandle erstellt wurde.

Ich habe bereits versucht, einen Griff auf dem Punkt Bericht zu erstellen ... aber das hat nicht funktioniert. Das Problem ist, ich habe keine Ahnung, was ich tue, und ich habe Google gesucht extensiv nur vage Antworten zu finden.

Bitte sagen Sie mir, wie Sie den Griff erstellen, bevor ich diesen Delegaten aufzurufen. Während Sie gerade dabei sind, geben Sie mir einige Möglichkeiten, wie ich diesen Code einfacher machen kann. Zum Beispiel nicht, daß ich zwei Funktionen zufügen wollen ... Ich hatte das zu tun, weil es keine Möglichkeit für mich, um ein Element zu finden aus der Logging-Klasse aufzurufen. Gibt es eine bessere Art und Weise zu erreichen, was ich tun muß?

Danke !!!

EDIT:

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

Anmelden ist mein RichTextBox1 (Log.Items.Add (Nachricht)) ich es umbenannt Log so ist es einfacher, in das Feld eintragen.

ich aber Updatelog (Nachricht) von einer anderen Form nenne ... lassen Sie mich die hier aktualisieren (auch wenn es keinen Unterschied macht, wo ich Updatelog (Meldung nennen) aus es gibt mir immer noch diesen Fehler)

Ihre Jungs gehen zu müssen, um die Dinge einfacher für mich machen ... und Beispiele. Ich verstehe nicht, die Hälfte von allem euch hier sagen ... Ich habe keine Ahnung, wie man mit Aufrufen von Methoden und Griffen zu arbeiten. Ich habe den Mist aus recherchiert zu ...

ZWEITE EDIT:

Ich glaube, ich habe das Problem liegt, aber nicht wissen, wie es zu beheben.

In meiner Logging-Klasse verwende ich diesen Code Mainclass zu erstellen:

statische Hauptmainclass = new Main ();

Ich bin einen völlig neuen Entwurf Replik Main () zu schaffen, einschließlich dem Anmelden (die richtextbox Ich versuche zu aktualisieren)

Wenn ich rufe Updatelog (Nachricht) Ich glaube, ich versuche, das Log (richtextbox) auf der zweiten Einheit von Main () auch bekannt als Mainclass zu aktualisieren. Natürlich wird diese Ausnahme werfen mich so zu tun, weil ich nicht einmal, dass die Nachbildung des aktuellen Haupt gesehen habe ich verwende.

Das ist das, was ich drehe für dank einer der Menschen, die eine Antwort gab:

Main mainClass = Application.OpenForms.OfType<Main>().First();
logAddDelegate = mainClass.logAdd; 
logAddDelegate(message);

ich brauche Mainclass nicht mit dem neuen Operator () zu erstellen, weil ich nicht will, einen neuen Entwurf des Formulars erstellen ist die aktuelle Form bearbeiten können, möchte.

Der obige Code nicht obwohl arbeiten, ich kann nicht einmal Anwendung finden. Ist das auch C # Syntax?

Wenn ich den obige Code bekommen zu arbeiten, ich denke, ich mein Problem lösen kann und schließlich lege dieses Problem nach ein paar Stunden der Suche nach Antworten auf Ruhe.

FINAL EDIT:

ich es herausgefunden dank einem der Benutzer unten. Hier ist meine aktualisierte Code:

Hauptformular Code:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        private static Main mainFormForLogging;
        public static Main MainFormForLogging
        {
            get
            {
                return mainFormForLogging;
            }
        }

        public Main()
        {
            InitializeComponent();
            if (mainFormForLogging == null)
            {
                mainFormForLogging = this;
            }
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {
            this.Log.BeginInvoke(new logAdd(add), new object[] { message });
        }

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            add("test");
            Logging.updateLog("testthisone");
            //DatabaseHandling.createDataSet();
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

Protokollierung Klassencode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {

        static Main mainClass = Main.MainFormForLogging;
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
War es hilfreich?

Lösung

Richtig, ich werde wieder starten.

Um zu verstehen, was geschieht, müssen Sie verstehen, wie .NET und Windows miteinander in Beziehung stehen. .NET läuft unter Windows und wickelt viele der nativen Win32-Konzepte wie ein Fenster, eine Listenansicht, eine editbox (der Win32 Name für eine Standard-Textbox). Dies bedeutet, dass Sie eine gültige .NET Instanz eines TextBox oder ein Formular haben, aber nicht die zugrunde liegende Windows-Version dieses Artikels haben (EditBox oder Fenster) vor. Wenn Handle wahr ist, wird die Windows-Version des Produkts erstellt.

Ihr Problem auftritt, weil etwas in der logAdd Methode führt vor dem Fenster des Formulars aufgerufen wird erstellt wurde. Dies bedeutet, irgendwo während der Inbetriebnahme, nachdem die Formularinstanz instanziiert wurde, aber bevor der Fenstergriff erstellt wurde, etwas versucht logAdd zu nennen. Wenn Sie einen Haltepunkt logAdd hinzufügen, sollten Sie in der Lage sein zu sehen, was diesen Anruf tut. Was finden Sie besteht darin, dass der Anruf auf der Hauptinstanz gemacht wird, um Sie in Ihrer Logger-Klasse erstellen und nicht die Hauptinstanz, die tatsächlich ausgeführt wird. Da der Logger Instanz niemals angezeigt wird, wird das Fenster-Handle nicht erstellt, und Sie Ihren Fehler so erhalten.

Die allgemeine Art und Weise läuft eine Anwendung Application.Run (new Main ()) in Ihrer Startmethode zu nennen, die in der Regel in der Program-Klasse ist und genannt Main. Sie benötigen Logger auf diese Instanz von Haupt zeigen.

Es gibt mehr Möglichkeiten, um die Instanz des Formulars, jeder mit seinen eigenen Vorbehalten zu bekommen, aber der Einfachheit halber können Sie die Instanz von der Hauptklasse selbst aussetzen. Zum Beispiel:

public partial class Main : Form
{
    private static Main mainFormForLogging;
    public static Main MainFormForLogging
    {
        get
        {
            return mainFormForLogging;
        }
    }

    public Main()
    {
        InitializeComponent();

        if (mainFormForLogging == null)
        {
            mainFormForLogging = this;
        }
    }

    protected void Dispose(bool disposing)
    {
         if (disposing)
         {
             if (this == mainFormForLogging)
             {
                mainFormForLogging = null;
             }
         }

         base.Dispose(disposing);
    }
}

Andere Tipps

Ich habe löste dies in der Vergangenheit der folgenden Methode:

private void invokeOnFormThread(MethodInvoker method)
{
    if (IsHandleCreated)
         Invoke(new EventHandler(delegate { method(); }));
    else
        method();
}

Anruf invokeOnFormThread statt Invoke. Es wird nur die Form des Threads verwenden, wenn ein Handle bereits erstellt wurde, sonst wird es den Thread des Anrufers verwendet werden.

Wenn Sie diese Fehlermeldung erhalten, ist es fast immer bedeutet, dass Sie versucht haben, auf eine Kontrolle oder Form zu handeln, bevor es tatsächlich erstellt wurde.

In WinForms, GUI-Elemente haben zwei semi-unabhängiges Leben: als Klassen im Speicher und als Entitäten in dem Betriebssystem. Als solches ist es möglich, eine Kontrolle in .net zu verweisen, die wurden noch nicht tatsächlich erstellt. Der „Griff wird erstellt“ bezieht sich auf eine Zahl auf die Steuerung durch das OS zugeordnet, die Programme zu ermöglichen, seine Eigenschaften zu verändern.

In diesem Fall können die meisten Fehler durch Setzen eines Flags am Ende des Formulars Ladeereignis beseitigt werden und versuchen, nur die Form der Kontrollen zu manipulieren, nachdem das Flag gesetzt worden ist.

Es ist ein Laufzeitfehler, kein Compiler-Fehler.

Ihr Formular, „Main“, hat angezeigt werden (daher ein Fenster-Handle erstellt), bevor Sie Anrufe BeginInvoke oder Invoke auf sie machen.

Was ich in der Regel in solchen Situationen zu tun ist es auf die Form verlassen, um festzustellen, ob es einen Aufruf an BeginInvoke oder Invoke verwenden muss. Sie können mit einem Aufruf an InvokeRequired (Check MSDN) testen, ob.

Also für den Anfang, ich loswerden der logAddDelegate Anruf bekommen würde in der Updatelog Methode des Loggin Klasse. So stellen Sie einen gerade Aufruf die Form ein Protokoll hinzuzufügen. Wie so:

public partial class Main : Form
{
    public Main()
    {
        InitializeComponent();
    }

    private delegate void AddNewLogMessageEventHandler(string message);

    public void AddLogMessage(string message)
    {
        object[] args = new object[1];
        args[0] = message;

        if (InvokeRequired)
            BeginInvoke(new AddNewLogMessageEventHandler(AddLog), args);
        else
            Invoke(new AddNewLogMessageEventHandler(AddLog), args);
    }

    private void AddLog(string message)
    {
        this.Log.Items.Add(message);
    }
 }

}

So Sie sehen können, das Formular selbst ist verantwortlich für die Bestimmung, ob es braucht die Methode asynchron oder nicht zu nennen.

Dies wird jedoch noch immer nicht möglich Laufzeitfehler beheben, weil Sie einen Anruf an die Form machen vor seinem angezeigt worden. Sie können überprüfen, ob der Griff des Formulars null ist oder nicht, und das wird zumindest können Sie überprüfen, ob Sie mit einem gültigen Formular zu tun hat.

neigt Dieser Fehler passieren, wenn Sie auf ein Fenster aufzurufen, die noch nicht ‚‘ gezeigt hat. Sind Sie sicher, dass Sie nicht eine zweite Instanz der Hauptklasse mit dem Code in der Logging-Klasse (genauer gesagt, die erste Zeile) zu schaffen? Es kann sein, dass die Hauptform Sie sich anmelden rufen ist nicht die Hauptform Sie suchen. Wenn Sie überprüfen möchten, fügen Sie einen Aufruf an „MainClass.Show ()“ nur in Ihrem Logging-Aufruf. Wenn Sie eine zweite Kopie des Hauptformulars erhalten auftauchen, dann ist das Problem ist, dass Ihre Logging-Klasse nicht verweist auf die richtige ‚Instanz‘ des Formulars.

Denken Sie an die Klasse als ‚Plan‘. Jede Instanz der Klasse (erstellt mit dem Wort ‚neu‘) ist eine weitere Aufgabe, aus dem Entwurf erstellt. Nur weil zwei Objekte (in diesem Fall Ihre zwei Hauptformen) den gleichen Entwurf teilen, bedeutet nicht, dass man sie untereinander austauschbar verwendet werden kann. In diesem Fall haben Sie bereits ein Hauptformular, und Sie wollen ‚Wiederverwendung‘ es. Sie können versuchen:

MainClass myMainForm = Application.OpenForms.OfType<MainClass>().First();
logAddDelegate = myMainForm.logAdd; 
logAddDelegate(message);

in Ihrer Log-Funktion statt, was Sie im Moment haben. Der Unterschied ist, dass der Aufruf von Application.OpenForms.OfType (). Zunächst wird die Anwendung gehen, und rufen Sie das IST-Hauptformular, das Sie sehen (technisch, wird es die erste Instanz davon abrufen) und Ihren Aufruf machen auf, dass bilden, direkt.

Hope, das hilft.

Dies ist im Fall eine andere Person mit diesem nach oben erwischt zu helfen. Mein Problem: VB.net: „Invoke oder BeginInvoke kann nicht auf einem Steuerelement aufgerufen werden, bis das Fenster-Handle erstellt wurde.“ Ich schloss eine Form, die eine Prozedur für das Ereignis hat nennt die Delegierten zu aktualisieren, ohne dass die Prozedur für das Ereignis zu entfernen.

Was ich getan habe: Wenn ich das Formular zu schließen, ich entfernte alle Handler und zugewiesen sie zurück, wenn ich die Form geöffnet. Es löste das Problem.

  

logAddDelegate (Nachricht);

Ich glaube, Sie dies fordern, bevor das Form_Load-Ereignis ausgelöst wurde. Fix Ihren Code zu warten, bis das Formular vor laden Aufruf logAddDelegate (...), das heißt vor dem Aufruf Logging.updateLog ()

Ist das Ihr genauer Code? Sie rufen this.Log.Items.Add(message); in Ihrem add (String) -Methode, aber Ihre Logging-Klasse wird Logging aufgerufen, sich nicht anmelden. Haben Sie eine andere Form vielleicht genannt Log? Wenn das Formular nicht erstellt wurde, wenn Sie das Add-Methode aufrufen, wird diese Ausnahme erhalten.

Ich fand das InvokeRequired nicht zuverlässig, so dass ich einfach nutzen

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top