C # de error de compilación: “invocar o BeginInvoke no puede ser llamado en un control hasta que se haya creado el identificador de ventana.”

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

Pregunta

Me acaba de publicar una pregunta acerca de cómo obtener un delegado para actualizar un cuadro de texto en otra forma. Justo cuando pensaba que tenía la respuesta utilizando la invocación ... esto sucede. Aquí está mi código:

Código del formulario principal:

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

}

Registro Código de clase:

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);
        }
    }
}
  • Error de compilación:

    fue InvalidOperationException no controlada - invocar o BeginInvoke no puede ser llamado en un control hasta el identificador de ventana ha sido creado.

Ya he intentado crear una manija en el elemento del registro ... pero que no funcionó. El problema es que no tengo ni idea de lo que estoy haciendo y he buscado Google ampliamente sólo para encontrar respuestas vagas.

Por favor, dígame cómo crear el mango antes de invocar este delegado. Mientras que usted está en él, dame algunas maneras en que puedo hacer que este código sea más sencilla. Por ejemplo, no quiero dos funciones ... Añadir tuviera que hacer eso porque no había manera para mí para encontrar un elemento para invocar a la clase de registro. ¿Hay una mejor manera de lograr lo que tengo que hacer?

Gracias !!!

EDIT:

Mi proyecto es bastante grande, pero estos son los únicos elementos que provocan este problema específico.

Iniciar sesión es mi RichTextBox1 (Log.Items.Add (mensaje)) Me cambió el nombre para iniciar sesión por lo que es más fácil volver a escribir.

Estoy llamando updateLog (mensaje) de una forma diferente, sin embargo ... déjame actualización que aquí (aunque no hace ninguna diferencia en que yo llamo updateLog (mensaje) de que todavía me da este error)

Ustedes van a tener que hacer las cosas más fácil para mí ... y dar ejemplos. No entiendo la mitad de lo que ustedes están diciendo aquí ... no tengo idea de cómo trabajar con la invocación de métodos y manijas. He investigado la basura fuera de ella también ...

SEGUNDO EDIT:

Creo haber localizado el problema, pero no sé cómo solucionarlo.

En mi clase de registro que utiliza este código para crear MainClass:

estática MainClass principal = new Principal ();

Estoy creando una réplica totalmente nuevo plan para Principal (), que incluye Iniciar sesión (RichTextBox Estoy intentando actualizar)

Cuando llamo updateLog (mensaje) Creo que estoy tratando de actualizar el registro (RichTextBox) en la segunda entidad de principal () también conocida como MainClass. Por supuesto, si lo hace tirarme esta excepción, porque ni siquiera he visto que la réplica de la corriente principal que estoy utilizando.

Esto es lo que me tiro para, gracias a una de las personas que dieron una respuesta:

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

Es necesario crear MainClass no con el nuevo operador () porque no quiero crear un nuevo modelo de la forma que quiero ser capaz de modificar la forma actual.

El código anterior no funciona, sin embargo, que ni siquiera puedo encontrar aplicación. Es que incluso sintaxis de C #?

Si puedo conseguir el código anterior funcione, creo que puedo resolver mi problema y finalmente dejar este problema para descansar después de un par de horas de búsqueda de respuestas.

EDITAR FINAL:

he descubierto gracias a uno de los usuarios de abajo. Aquí está mi código de actualización:

Código del formulario principal:

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

}

Registro Código de clase:

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);
        }
    }
}
¿Fue útil?

Solución

Bien, voy a empezar de nuevo.

Con el fin de entender lo que está sucediendo, es necesario entender cómo .NET y Windows se relacionan entre sí. .NET se ejecuta en Windows y envuelve muchos de los conceptos, Win32 nativas como una ventana, una vista de lista, un cuadro de edición (el nombre de Win32 para un cuadro de texto estándar). Esto significa que usted puede tener una instancia de .NET válido de un cuadro de texto o una forma, pero no tienen la versión de Windows subyacente de ese tema (cuadro de edición, o ventana) todavía. Cuando HandleCreated es cierto, se crea la versión de Windows del artículo.

Su problema se produce porque algo está provocando el método logAdd ser llamado antes de que se haya creado la ventana del formulario. Esto significa que en algún momento durante su puesta en marcha después de que la instancia de formulario se ha creado una instancia pero antes de que se haya creado el identificador de la ventana, algo está tratando de llamar logAdd. Si se agrega un punto de interrupción a logAdd, usted debería ser capaz de ver lo que está haciendo esa llamada. Lo que se encontrará es que la llamada se está realizando en la instancia principal que cree en su clase de logger y no la instancia principal que se ejecuta realmente. A medida que la instancia registrador nunca se muestra, no se crea el identificador de ventana, y así se obtiene el error.

La forma general de una aplicación se ejecuta es llamar Application.Run (nueva Principal ()) en su método de inicio, que es por lo general en la clase del Programa y llama principal. Es necesario su registrador para que apunte a esta instancia del principal.

Hay varias maneras de obtener la instancia del formulario, cada uno con sus propias advertencias, pero por simplicidad que podrían exponer la instancia de la clase principal en sí. Por ejemplo:

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

Otros consejos

He resuelto esto en el pasado mediante el método siguiente:

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

Llamada invokeOnFormThread en lugar de invocación. Sólo utilizará el hilo de la forma, si ya se ha creado un mango, de lo contrario, utilizar el hilo de la persona que llama.

Cuando se obtiene este error, casi siempre significa que usted ha intentado actuar en una forma de control o antes de que se crea realmente.

En WinForms, elementos de la GUI tienen dos vidas semi-independientes: como clases de memoria y como entidades en el sistema operativo. Como tal, es posible hacer referencia a un control en .NET que en realidad no se ha creado todavía. La "manija que se está creando" se refiere a tener un número asignado al control por el sistema operativo para permitir que los programas para manipular sus propiedades.

En este caso, la mayoría de los errores pueden ser eliminados mediante el establecimiento de una bandera al final del evento de carga de la forma y sólo el intento de manipular los controles del formulario después de que la bandera se ha establecido.

Es un error de ejecución, no un error del compilador.

Su forma, "Principal", tiene que ser mostrado (por lo tanto, un identificador de ventana creada) antes de poder hacer llamadas a BeginInvoke o invocar en él.

Lo que suele hacer en estas situaciones es dejar que sea la forma de determinar si necesita usar una llamada a BeginInvoke o invocación. Se puede probar que con una llamada a InvokeRequired (marque MSDN).

Así que para empezar, me gustaría conseguir librarse de la llamada logAddDelegate en el método de la clase updateLog Loggin. Simplemente hacer una llamada directamente al formulario para agregar un registro. De esta manera:

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

}

Así se puede ver, el propio formulario es el encargado de determinar si es necesario llamar al método de forma asíncrona o no.

Sin embargo, esto todavía no solucionará el error de ejecución, porque usted está haciendo una llamada a la forma antes de su sido expuestas. Usted puede comprobar para ver si la manija de la forma es nulo o no, y que tendrá al menos permitirá verificar si está o no está tratando con una forma válida.

Ese error que suele ocurrir si se invoca en una ventana que aún no ha sido 'muestra'. ¿Estás seguro de que no va a crear una segunda instancia de la clase principal con su código de la clase de registro (en concreto, la primera línea)? Puede ser que la forma principal que está llamando conectarse NO es la forma principal por la que está viendo. Si desea comprobar, añadir una llamada a "MainClass.Show ()" justo dentro de su registro de llamadas. Si se obtiene una segunda copia del formulario principal que se levante, entonces el problema es que la clase de registro no se está refiriendo a la derecha 'ejemplo' de su formulario.

Piense en la clase como un 'modelo'. Cada instancia de la clase (creado con la palabra 'nuevo') es otro objeto, creado a partir del modelo. El hecho de que dos objetos (en este caso, sus dos formas principales) comparten el mismo modelo, no significa que se puede utilizar de forma indistinta. En este caso, usted ya tiene un formulario principal, y desea que 're-uso'. Usted puede tratar de:

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

dentro de su función de registro en lugar de lo que tiene actualmente. La diferencia es que el llamado a Application.OpenForms.OfType (). En primer lugar voy a entrar en su aplicación, y recuperar la forma principal actual que está viendo (técnicamente, se recuperará la primera instancia del mismo) y hacer que su invocación en ese formar, directamente.

Espero que esto ayude.

Esto es para ayudar en caso de cualquier otra persona que quedó atrapado con esto. Mi problema: VB.net: “invocar o BeginInvoke no pueden ser llamados en un control hasta que se haya creado el identificador de ventana.” Cerré una forma que tiene un controlador para el evento llamo para actualizar el delegado, sin quitar el controlador para el evento.

Lo que hice: Al cerrar el formulario, quité todos los manipuladores, y les asigna de nuevo cuando abre el formulario. Se resolvió el problema.

  

logAddDelegate (mensaje);

Creo que se llama a esta antes del evento Form_Load se ha planteado. Fijar el código que esperar a que la forma de cargar antes de llamar logAddDelegate (...) es decir, antes de llamar a Logging.updateLog ()

Esta es su código exacto? Que está llamando this.Log.Items.Add(message); en su método (cadena) complemento, pero la clase de registro se llama registro, no registra. ¿Tienes otra forma llamada de registro, tal vez? Si esa forma no se ha creado cuando se llama al método add, obtendrá esta excepción.

He encontrado el InvokeRequired no confiable, por lo que simplemente usar

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top