C # erro de compilação: “Invoke ou BeginInvoke não pode ser chamado em um controle até que o identificador de janela foi criado.”

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

Pergunta

Acabei de publicar uma pergunta sobre como obter um delegado para atualizar uma caixa de texto em outro formulário. Apenas quando eu pensei que eu tinha a resposta usando Invoke ... isso acontece. Aqui está o meu código:

Main Código Forma:

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

}

Logging Código 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);
        }
    }
}
  • Erro de compilação:

    InvalidOperationException foi não tratada - Invoke ou BeginInvoke não pode ser chamado em um controle até o identificador de janela foi criado.

Já tentou criar uma alça sobre o item Log ... mas isso não funcionou. O problema é que eu não tenho idéia do que estou fazendo e tenho procurado Google extensivamente apenas para encontrar respostas vagas.

Por favor me diga como criar a alça antes de invocar este delegado. Enquanto você está nisso, me dê algumas maneiras que eu posso fazer esse código mais simples. Por exemplo, eu não quero duas funções Adicionar ... Eu tinha que fazer isso, porque não havia nenhuma maneira para mim encontrar um item para invocar a partir da classe Logging. Existe uma maneira melhor de realizar o que eu preciso fazer?

Obrigado !!!

EDIT:

Meu projeto é bastante grande, mas estes são os únicos itens que causam esse problema específico.

Log é a minha RichTextBox1 (Log.Items.Add (mensagem)) I renomeou para Log por isso é mais fácil de digitar novamente.

Eu estou chamando updateLog (mensagem) de uma forma diferente embora ... deixe-me atualizar isso aqui (embora isso não faz diferença onde eu chamo updateLog (mensagem) de que ainda me dá esse erro)

Vocês vão ter que fazer as coisas mais simples para mim ... e fornecer exemplos. Eu não entendo metade de tudo que vocês estão dizendo aqui ... Eu não tenho idéia de como trabalhar com invocação dos métodos e alças. Eu pesquisei o crap fora dele também ...

SEGUNDO EDIT:

Eu acredito que eu tenha localizado o problema, mas não sei como corrigi-lo.

Na minha classe de log eu uso este código para criar MainClass:

estática principal MainClass = new Main ();

Estou criando um inteiramente nova réplica plano para Main (), incluindo Log (o richtextbox Estou tentando atualização)

Quando eu chamo updateLog (mensagem) Eu acredito que eu estou tentando atualizar o Log (richtextbox) sobre a segunda entidade de Main () também conhecido como MainClass. Claro, isso vai me jogar essa exceção, porque eu não vi mesmo que replica da corrente principal que estou usando.

Este é o que estou atirando para, graças a uma das pessoas que deram uma resposta:

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

Eu preciso criar MainClass não com o novo operador () porque eu não quero criar um novo projeto da forma que eu quero ser capaz de editar a forma atual.

O código acima não funciona, porém, eu não posso mesmo encontrar aplicação. É que mesmo sintaxe C #?

Se eu conseguir o código acima para o trabalho, eu acho que eu posso resolver meu problema e, finalmente, colocar este problema para descansar depois de um par de horas de busca por respostas.

edição final:

Eu descobri graças a um dos usuários abaixo. Aqui está o meu código atualizado:

Main Código Forma:

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

}

Logging Código 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);
        }
    }
}
Foi útil?

Solução

Certo, eu vou começar de novo.

A fim de entender o que está acontecendo, você precisa entender como .NET e Windows se relacionam entre si. .NET roda em Windows e envolve muitos dos conceitos, Win32 nativas como uma janela, um listview, um editbox (o nome Win32 para uma caixa de texto padrão). Isso significa que você pode ter uma instância .NET válido de um TextBox ou um formulário, mas não têm a versão do Windows subjacente desse item (EditBox, ou janela) ainda. Quando HandleCreated é verdade, é criada a versão Windows do item.

Seu problema está ocorrendo porque algo está levando ao método logAdd ser chamado antes da janela do formulário foi criado. Isso em algum lugar meio durante a sua inicialização depois que a instância Form foi instanciado, mas antes do identificador de janela foi criado, algo está tentando chamar logAdd. Se você adicionar um ponto de interrupção para logAdd, você deve ser capaz de ver o que está fazendo essa chamada. O que você vai encontrar é que a chamada está sendo feita na instância principal de criar em sua classe logger e não a instância principal que está atualmente em execução. Como a instância logger nunca é mostrado, o identificador de janela não é criado, e de modo a obter o seu erro.

A forma geral de um aplicativo é executado é chamar Application.Run (new Main ()) no seu método de inicialização, que é geralmente na classe de programa e chamado principal. Você precisa do seu logger para apontar para esta instância do principal.

Existem várias maneiras de obter a instância do formulário, cada um com suas próprias advertências, mas, para simplificar, você poderia expor a instância off da classe principal em si. Por exemplo:

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

Outras dicas

Eu ter resolvido isso no passado com o seguinte método:

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

Chamada invokeOnFormThread vez de Invoke. Ele só vai usar fio do formulário se um identificador já foi criado, caso contrário ele irá usar fio do chamador.

Quando você receber esse erro, quase sempre significa que você tentou agir em um controle ou formulário antes que ele realmente foi criado.

No WinForms, elementos GUI tem duas vidas semi-independentes: como aulas na memória e como entidades do sistema operacional. Como tal, é possível fazer referência a um controle em .net que realmente não foi criado ainda. O "punho que está sendo criado" refere-se a ter um número atribuído ao controle pelo sistema operacional para permitir que programas para manipular suas propriedades.

Neste caso, a maioria dos erros pode ser eliminado, definindo uma bandeira no final do evento de carregamento do formulário e apenas tentar manipular os controles do formulário depois que a bandeira foi definido.

É um erro de execução, e não um erro do compilador.

Seu Form, "Main", tem que ser apresentada (daí um identificador de janela criado) antes que você possa fazer chamadas para BeginInvoke ou invocar sobre ele.

O que eu costumo fazer nestas situações é deixá-lo até o Formulário para determinar se ele precisa usar uma chamada para BeginInvoke ou Invoke. Você pode testar isso com uma chamada para InvokeRequired (verifique MSDN).

Então, para começar, eu livrar-se da chamada logAddDelegate no método updateLog da classe Loggin. Basta fazer uma chamada directamente para o formulário para adicionar um registro. Como assim:

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

}

Assim você pode ver, o próprio formulário está encarregado de determinar se ele precisa chamar o método de forma assíncrona ou não.

No entanto, isso ainda não vai corrigir o seu erro de execução, porque você está fazendo uma chamada para o formulário antes de sua sido exibido. Você pode verificar para ver se Handle do formulário é nulo ou não, e que, pelo menos permitir-lhe para verificar se ou não você está lidando com uma forma válida.

Esse erro tende a acontecer se você invocar em uma janela que não tenha ainda sido 'mostrado'. Tem certeza de que não estamos criando uma segunda instância da classe principal com o seu código na classe Logging (especificamente, a primeira linha)? Pode ser que a principal forma que você está chamando log não é a principal forma que você está olhando. Se você quiser verificar, adicione uma chamada para "MainClass.Show ()" apenas dentro de sua chamada de registro. Se você receber uma segunda cópia do formulário principal surgindo, então o problema é que a sua classe de log não faz referência a 'instância' direito de seu formulário.

Pense a classe como um 'modelo'. Cada instância da classe (criado com a palavra 'novo') é outro objeto, criado a partir do projeto. Só porque dois objetos (neste caso, suas duas formas principais) compartilham o mesmo modelo, não significa que você pode usá-los alternadamente. Neste caso, você já tem um formulário principal, e você quer 'reutilização' it. Você pode tentar:

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

dentro de sua função de log em vez do que você tem atualmente. A diferença é que a chamada para Application.OpenForms.OfType (). Primeiro vou entrar em sua aplicação, e recuperar a principal forma real que você está vendo (tecnicamente, ele irá recuperar a primeira instância dele) e fazer a sua invocação em que formar, directamente.

Espero que isso ajude.

Esta é a ajuda no caso de qualquer outra pessoa foi pego com isso. Meu problema: VB.net: “Invoke ou BeginInvoke não pode ser chamado em um controle até que o identificador de janela foi criado.” Fechei um formulário que tem um manipulador para o evento am chamando para atualizar o delegado, sem retirar o manipulador para o evento.

O que eu fiz: Quando eu fechar o formulário, tirei todos os manipuladores, e atribuiu-los de volta quando eu abriu o formulário. Ele resolveu o problema.

logAddDelegate (mensagem);

Eu acho que você está chamando isso antes do evento Form_Load foi levantada. Corrigir o seu código de esperar para que o formulário de carga antes de chamar logAddDelegate (...) ou seja, antes de chamar Logging.updateLog ()

É este o seu código exato? Você está chamando this.Log.Items.Add(message); em seu método add (string), mas a sua classe de log é chamado de Registro, não Log. Você tem uma outra forma chamado Log talvez? Se essa forma não foi criado quando você chamar o método add, você receberá esta exceção.

Eu encontrei o InvokeRequired não confiável, então eu simplesmente usar

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top