C # Erreur de compilation: « Invoquez ou BeginInvoke ne peut pas être appelée sur un contrôle jusqu'à ce que la poignée de fenêtre a été créée. »

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

Question

Je viens de publier une question sur la façon d'obtenir un délégué de mettre à jour une zone de texte sur une autre forme. Juste au moment où je pensais avoir la réponse en utilisant Invoke ... cela arrive. Voici mon code:

Code principal Forme:

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

}

Enregistrement Code de 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);
        }
    }
}
  • Erreur de compilation:

    InvalidOperationException était unhandled - ou Invoke BeginInvoke ne peut pas être appelée sur un contrôle jusqu'à ce que la poignée de fenêtre a été créée.

Je l'ai déjà essayé de créer une poignée sur l'élément Log ... mais cela ne fonctionne pas. Le problème est que je ne savent absolument pas ce que je fais et je l'ai cherché Google largement seulement pour trouver des réponses vagues.

S'il vous plaît me dire comment créer la poignée avant que j'invoque ce délégué. Pendant que vous y êtes, me donner quelques moyens que je peux rendre ce code plus simple. Par exemple, je ne veux pas deux Ajouter des fonctions ... Je devais le faire parce qu'il n'y avait aucun moyen pour moi de trouver un élément pour appeler de la classe de journalisation. Y at-il une meilleure façon d'accomplir ce que je dois faire?

Merci !!!

EDIT:

Mon projet est assez important, mais ce sont les seuls éléments qui causent ce problème spécifique.

Connexion est mon RichTextBox1 (Log.Items.Add (message)) Je rebaptisèrent journaliser est donc plus facile à retaper.

Je fais appel updateLog (message) à partir d'une forme différente mais ... permettez-moi de mettre à jour que ici (même si elle ne fait aucune différence où j'appelle updateLog (message) de celui-ci me donne toujours cette erreur)

Les gars, vous allez devoir rendre les choses plus simples pour moi ... et donner des exemples. Je ne comprends pas la moitié de tout ce que vous dites les gars ici ... Je n'ai pas la moindre idée sur la façon de travailler avec Invoquer des méthodes et des poignées. Je l'ai fait des recherches sur la merde hors de trop ...

DEUXIÈME EDIT:

Je crois avoir trouvé le problème, mais ne sais pas comment le résoudre.

Dans ma classe d'exploitation forestière j'utiliser ce code pour créer MainClass:

statique principal MainClass = new Main ();

Je suis en train de créer une réplique de modèle entièrement nouveau à Main (), y compris Connexion (RichTextBox j'essaie de mettre à jour)

Quand j'appelle updateLog (message) Je crois que je suis en train de mettre à jour le journal (richtextbox) sur la seconde entité de Main () autrement connu sous le nom MainClass. Bien sûr, cela lui permet de me jeter cette exception parce que je n'ai même pas vu que réplique du courant principal J'utilise.

est ce que je suis prise de vue pour, grâce à l'une des personnes qui a donné une réponse:

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

Je dois créer MainClass pas avec l'opérateur new () parce que je ne veux pas créer un nouveau plan de la forme que je veux être en mesure de modifier la forme actuelle.

Le code ci-dessus ne fonctionne pas bien, je ne peux même pas trouver application. Est-ce que même la syntaxe C #?

Si je peux obtenir le code ci-dessus fonctionne, je pense que je peux résoudre mon problème et enfin poser ce problème pour se reposer après quelques heures de recherche pour trouver des réponses.

FINAL EDIT:

j'ai tout compris grâce à l'un des utilisateurs ci-dessous. Voici mon code mis à jour:

Code principal Forme:

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

}

Enregistrement Code de 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);
        }
    }
}
Était-ce utile?

La solution

Bon, je vais commencer à nouveau.

Pour comprendre ce qui se passe, vous avez besoin de comprendre comment .NET et Windows se rapportent les uns aux autres. .NET fonctionne sous Windows et enveloppe la plupart des natifs, des concepts Win32 comme une fenêtre, un listview, un editbox (le nom Win32 pour une zone de texte standard). Cela signifie que vous pouvez avoir une instance .NET valide d'une zone de texte ou un formulaire, mais pas la version de Windows sous-jacente de cet élément (EditBox ou fenêtre) encore. Lorsque HandleCreated est vrai, la version Windows de l'élément est créé.

Votre problème se produit parce que quelque chose est conduit à la méthode logAdd convocation devant la fenêtre du formulaire a été créé. Cela signifie quelque part lors de votre démarrage après l'instance de formulaire a été instancié, mais avant que la poignée de fenêtre a été créé, quelque chose essaie d'appeler logAdd. Si vous ajoutez un point d'arrêt à logAdd, vous devriez être en mesure de voir ce que fait cet appel. Ce que vous trouverez que l'appel est fait sur l'instance principale vous créez dans votre classe enregistreur et pas l'instance principale qui est en fait en cours d'exécution. Comme l'exemple de l'enregistreur ne se montre, la poignée de fenêtre ne se crée pas, et vous obtenez votre erreur.

La façon générale une application fonctionne est d'appeler Application.Run (nouveau Main ()) dans votre méthode de démarrage, qui est habituellement dans la classe du programme et appelé Main. Vous avez besoin de votre enregistreur pour pointer vers cette instance de principal.

Il y a plusieurs façons d'obtenir l'instance de la forme, chacun avec ses propres mises en garde, mais par souci de simplicité vous pourriez exposer l'instance de la classe principale elle-même. Par exemple:

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

Autres conseils

Je l'ai résolu dans le passé en utilisant la méthode suivante:

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

Appel au lieu de Invoke invokeOnFormThread. Il n'utilisera le fil de la forme si une poignée a déjà été créé, sinon il utilisera le fil de l'appelant.

Lorsque vous obtenez cette erreur, cela signifie presque toujours que vous avez tenté d'agir sur un contrôle ou sous forme avant qu'il ne soit effectivement créée.

En WinForms, des éléments de l'interface graphique ont deux vies semi-indépendantes: que les classes en mémoire et que les entités du système d'exploitation. En tant que tel, il est possible de faire référence à un contrôle en .net qui n'a pas encore été réellement créé. La « poignée étant créé » fait référence à avoir un numéro attribué au contrôle par le système d'exploitation pour permettre aux programmes de manipuler ses propriétés.

Dans ce cas, la plupart des erreurs peuvent être éliminés en mettant un drapeau à la fin de l'événement de chargement du formulaire et que tenter de manipuler les contrôles du formulaire après que le drapeau a été défini.

Il est une erreur d'exécution, pas une erreur du compilateur.

Votre formulaire, « Main », doit être affiché (donc une poignée de fenêtre créée) avant de pouvoir faire des appels à BeginInvoke ou Invoke sur elle.

Ce que je fais habituellement dans ces situations est laisser place au formulaire pour déterminer si elle a besoin d'utiliser un appel à BeginInvoke ou Invoke. Vous pouvez tester cela avec un appel à InvokeRequired (vérifier MSDN).

Donc, pour commencer, je me débarrasser de l'appel logAddDelegate dans la méthode updateLog de classe Loggin. Il suffit de faire un appel directement au formulaire pour ajouter un journal. Comme ceci:

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

}

Vous pouvez voir, le formulaire lui-même est chargé de déterminer si elle a besoin d'appeler la méthode de façon asynchrone ou non.

Cependant, ce ne sera pas encore réparer votre erreur d'exécution, parce que vous faites un appel à la forme avant son été affichée. Vous pouvez vérifier si la poignée de la forme est nulle ou non, et qui au moins vous permettre de vérifier si vous êtes ou non traiter un formulaire valide.

Cette erreur a tendance à se produire si vous invoquez sur une fenêtre qui n'a pas encore été « montré ». Etes-vous sûr que vous n'êtes pas créer une deuxième instance de la classe principale avec votre code dans la classe d'enregistrement (en particulier, la première ligne)? Il se peut que la principale forme que vous appelez une connexion est pas la principale forme que vous regardez. Si vous voulez vérifier, ajouter un appel à « MainClass.Show () » juste à l'intérieur de votre appel d'enregistrement. Si vous obtenez une deuxième copie de la forme principale apparaître, le problème est que votre classe d'enregistrement ne référence pas la « instance » droit de votre formulaire.

Pensez à la classe comme un « plan ». Chaque instance de la classe (créé avec le mot « nouveau ») est un autre objet, créé à partir du plan. Tout simplement parce que deux objets (dans ce cas, vos deux principales formes) partagent le même plan, ne signifie pas que vous pouvez les utiliser de manière interchangeable. Dans ce cas, vous avez déjà une forme principale, et que vous voulez « réutilisation », il. Vous pouvez essayer:

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

dans votre fonction de journal au lieu de ce que vous avez actuellement. La différence est que l'appel à Application.OpenForms.OfType (). Tout d'abord ira dans votre application, et récupérer la forme principale RÉEL que vous voyez (techniquement, il récupérera la première instance de celui-ci) et faites votre appel sur cette former, directement.

Hope this helps.

est d'aider dans le cas où une autre personne a été pris à cet égard. Mon problème: VB.net: « Invoke ou BeginInvoke ne peut pas être appelée sur un contrôle jusqu'à ce que la poignée de fenêtre a été créée. » Je fermais une forme qui a un gestionnaire pour l'événement vous appelle à mettre à jour le délégué, sans enlever le gestionnaire pour l'événement.

Ce que je l'ai fait: Quand je ferme la forme, je l'ai enlevé tous les gestionnaires et les réaffecté en ouvrant la forme. Il a résolu le problème.

  

logAddDelegate (message);

Je pense que vous appelez cela avant l'événement Form_Load a été soulevée. Fixer votre code d'attendre le formulaire pour charger avant d'appeler logAddDelegate (...) à savoir avant d'appeler Logging.updateLog ()

Est-ce votre code exact? Vous appelez dans votre add this.Log.Items.Add(message); (string) méthode, mais votre classe d'enregistrement est appelé Logging, pas le journal. Avez-vous une autre forme appelée Log peut-être? Si cette forme n'a pas été créée lorsque vous appelez la méthode add, vous obtiendrez cette exception.

J'ai trouvé le pas fiables InvokeRequired, donc j'utiliser simplement

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top