C # errore di compilazione: “Invoke o BeginInvoke non può essere chiamato su un controllo fino a quando è stata creata la maniglia della finestra.”

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

Domanda

Ho appena pubblicato una domanda su come ottenere un delegato per aggiornare una casella di testo su un altro modulo. Proprio quando pensavo che ho avuto la risposta utilizzando Invoke ... questo accade. Ecco il mio codice:

principale Codice del modulo:

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();
    }

}

Registrazione Codice Classe:

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);
        }
    }
}
  • Errore di compilazione:

    InvalidOperationException era non gestita - Richiamare o BeginInvoke non può essere chiamato su un controllo fino l'handle di finestra è stata creata.

Ho già provato a creare una maniglia sulla voce Log ... ma che non ha funzionato. Il problema è non ho idea di quello che sto facendo e ho cercato di Google ampiamente solo per trovare risposte vaghe.

La prego di dirmi come creare il manico prima di invoco questo delegato. Mentre si è in esso, dammi qualche modo posso rendere questo codice più semplice. Per esempio, io non voglio due aggiungere funzioni ... ho dovuto farlo perché non c'era modo per me trovare una voce per invocare dalla classe registrazione. C'è un modo migliore per realizzare ciò che devo fare?

Grazie !!!

Modifica

Il mio progetto è abbastanza grande, ma questi sono gli unici elementi che causano questo problema specifico.

Accedi è il mio RichTextBox1 (Log.Items.Add (messaggio)) ho rinominato a Log così è più facile digitare nuovamente.

Chiedo updateLog (messaggio) da un modulo diverso però ... mi permetta di aggiornare che qui (anche se non fa alcuna differenza dove mi chiamo updateLog (messaggio) da ancora mi dà questo errore)

Voi ragazzi stanno andando ad avere per rendere le cose più semplici per me ... e fornire esempi. Non capisco la metà di tutto quello che voi ragazzi state dicendo qui ... Non ho nessuna idea su come lavorare con Invocazione di metodi e maniglie. Ho ricercato il crap fuori di esso troppo ...

SECONDO EDIT:

Credo di aver individuato il problema, ma non so come risolvere il problema.

Nella mia classe di registrazione Io uso questo codice per creare mainClass:

statico principale mainClass = new Main ();

Sto creando una del tutto nuova replica progetto per Main (), tra cui Accedi (RichTextBox sto cercando di aggiornare)

Quando chiamo updateLog (messaggio) Credo che sto cercando di aggiornare il registro (RichTextBox) sulla seconda entità di Main () altrimenti noto come mainClass. Naturalmente, così facendo mi passi questa eccezione perché non ho ancora visto che replica della corrente principale che sto usando.

Questo è quello che sto girando per, grazie ad una delle persone che ha dato una risposta:

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

Ho bisogno di creare mainClass non con l'operatore new () perché non voglio creare una nuova matrice della forma voglio essere in grado di modificare la forma attuale.

Il codice di cui sopra non funziona, però, non riesco nemmeno a trovare applicazione. È che anche sintassi C #?

Se posso ottenere il codice di cui sopra al lavoro, credo di poter risolvere il mio problema e, infine, porre questo problema a riposare dopo un paio di ore di ricerca di risposte.

Modifica FINALE:

ho capito grazie a uno degli utenti che seguono. Qui è il mio codice aggiornato:

principale Codice del modulo:

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();
    }

}

Registrazione Codice Classe:

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);
        }
    }
}
È stato utile?

Soluzione

A destra, ho intenzione di ricominciare.

Al fine di capire cosa sta succedendo, è necessario capire come .NET e Windows si riferiscono l'uno all'altro. .NET gira su Windows e avvolge molti dei concetti, Win32 native come una finestra, un controllo ListView, un EditBox (il nome Win32 per una casella di testo standard). Questo significa che è possibile avere un'istanza .NET valido di un TextBox o di un modulo, ma non hanno la versione base di Windows di tale elemento (EditBox, o finestra) ancora. Quando HandleCreated è vero, viene creata la versione Windows del prodotto.

Il problema si è verificato perché qualcosa sta portando al metodo logAdd essere chiamato prima della finestra del form è stato creato. Ciò significa che da qualche parte durante il vostro avvio dopo l'istanza modulo è stato istanziato, ma prima che la maniglia della finestra è stata creata, qualcosa sta cercando di chiamare logAdd. Se si aggiunge un punto di interruzione per logAdd, si dovrebbe essere in grado di vedere cosa sta facendo quella chiamata. Cosa si può trovare è che la chiamata è in corso sull'istanza principale si crea nella classe logger e NON l'istanza principale che è effettivamente in esecuzione. Come l'istanza logger non viene mai mostrato, l'handle di finestra non viene creato, e in modo da ottenere il vostro errore.

Il modo più generale di un'applicazione viene eseguita è quella di chiamare Application.Run (nuovo Main ()) nel metodo di avvio, che di solito è nella classe di Programma e chiamato principale. È necessario il logger per puntare a questa istanza di principale.

Ci sono diversi modi per ottenere l'istanza del form, ognuno con le proprie riserve, ma per semplicità si potrebbe esporre l'istanza di fuori della classe principale in sé. Ad esempio:

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);
    }
}

Altri suggerimenti

Ho risolto questo in passato, utilizzando il seguente metodo:

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

Chiama invokeOnFormThread invece di Invoke. Userà unico filo del form se un manico è già stato creato, altrimenti userà filo del chiamante.

Quando si ottiene questo errore, significa quasi sempre che hai tentato di agire su un controllo o form prima che fosse effettivamente creato.

In WinForms, elementi della GUI hanno due vite semi-indipendenti: le classi in memoria e come entità nel sistema operativo. Come tale, è possibile fare riferimento a un controllo in Netto che non è stato effettivamente ancora creato. Il "manico essendo creato" si riferisce ad avere un numero assegnato al controllo da parte del sistema operativo per consentire ai programmi di manipolare le proprietà.

In questo caso, la maggior parte degli errori possono essere eliminati impostando un flag al termine dell'evento di carico del modulo e solo il tentativo di manipolare i controlli della maschera dopo tale flag è stato impostato.

E 'un errore di runtime, non un errore del compilatore.

Il Modulo, "Main", deve essere visualizzato (quindi un handle di finestra creato) prima di poter effettuare chiamate a BeginInvoke o invocare su di esso.

Quello che faccio di solito in queste situazioni è lasciare fino al modulo per determinare se ha bisogno di utilizzare una chiamata a BeginInvoke o invocare. È possibile verificare che con una chiamata a InvokeRequired (verificare MSDN).

Quindi, per cominciare, mi piacerebbe sbarazzarsi della chiamata logAddDelegate nel metodo updateLog della classe Loggin. Basta fare una chiamata direttamente al modulo per aggiungere un registro. In questo modo:

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);
    }
 }

}

Così si può vedere, la forma stessa è responsabile di determinare se ha bisogno di chiamare il metodo in modo asincrono o meno.

Tuttavia, questo ancora non risolvere il tuo errore di runtime, perché si sta effettuando una chiamata per la forma prima della sua stata mostrata. È possibile controllare per vedere se l'handle della maschera è nullo o no, e che sarà, almeno permetterà di verificare se hai a che fare con una forma valida.

Tale errore tende ad accadere se si richiama su una finestra che non è ancora stato 'mostrato'. Sei sicuro che non stai creando una seconda istanza della classe principale con il codice nella classe di registrazione (in particolare, la prima linea)? Può essere che la forma principale che si sta chiamando accedere non è la forma principale che si sta guardando. Se si desidera controllare, aggiungere una chiamata a "MainClass.Show ()" appena dentro la chiamata di registrazione. Se si ottiene una seconda copia del modulo principale spuntare, allora il problema è che la classe di registrazione non fa riferimento il diritto 'istanza' del modulo.

Si pensi alla classe come un 'progetto'. Ogni istanza della classe (creato con la parola 'nuovo') è un altro oggetto, creato dal progetto. Solo perché due oggetti (in questo caso, i tuoi due forme principali) condividono lo stesso progetto, non significa che è possibile utilizzare in modo intercambiabile. In questo caso, si dispone già di un modulo principale, e si vuole 'riutilizzo' esso. Si può provare:

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

all'interno della vostra funzione di log invece di quello che hanno attualmente. La differenza è che la chiamata a Application.OpenForms.OfType (). In primo luogo andrà nella vostra applicazione, e recuperare la forma reale principale che si sta vedendo (tecnicamente, si recupererà la prima istanza di esso) e rendere la vostra invocazione su quel formare, direttamente.

Spero che questo aiuti.

Questo è quello di aiutare in caso di qualsiasi altra persona ha catturato con questo. Il mio problema: VB.net: “Invoke o BeginInvoke non può essere chiamato su un controllo fino a quando è stata creata la maniglia della finestra.” Ho chiuso una forma che ha un gestore per l'evento invito alla aggiornare il delegato, senza rimuovere il gestore per l'evento.

Quello che ho fatto: Quando chiudo la forma, ho rimosso tutti i gestori, e li assegnato indietro quando ho aperto il modulo. E 'risolto il problema.

  

logAddDelegate (messaggio);

Credo che si sta chiamando prima l'evento Form_Load è stata sollevata. Fissare il codice per attendere che il modulo per caricare prima di chiamare logAddDelegate (...) vale a dire prima di chiamare Logging.updateLog ()

È questo il tuo codice esatto? Si sta chiamando this.Log.Items.Add(message); nel metodo Add (string), ma la classe di registrazione si chiama registrazione, non registra. Hai un'altra forma chiamato Log forse? Se questo modulo non è stato creato quando si chiama il metodo Add, si otterrà questa eccezione.

Ho trovato la InvokeRequired non sono affidabili, così ho semplicemente usare

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top