2011-08-24 16 views
15

me sale el siguiente excepción lanzada:invocar o BeginInvoke no pueden ser llamados en un control hasta que el identificador de ventana se ha creado

invocar o BeginInvoke no pueden ser llamados en un control hasta que se haya creado el identificador de ventana.

Este es mi código:

if (InvokeRequired) 
{ 
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
} 
else 
    Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 

encontré páginas sobre este tema en este sitio, pero no sé lo que está mal.

+1

Sin saber más sobre el problema, suena como que está invocando un evento antes de que su forma está totalmente creado/inicializado, o en otro hilo en algún punto en el que no deben' t ser –

+1

Si tiene temporizadores en ejecución (System.Timers o System.Threading), compruebe si están causando que este código se ejecute en un formulario que no se ha construido completamente o está Disposed. –

+0

¿Dónde está este código, qué método o controlador de eventos? – Kev

Respuesta

47

La diferencia entre Invoke y BeginInvoke es que la primera es sincrónica (espera la finalización) mientras que la última es asíncrona (tipo de disparar y olvidar). Sin embargo, ambos funcionan publicando un mensaje en el bucle de mensaje de UI que hará que el delegado se ejecute cuando llegue a ese mensaje.

La propiedad InvokeRequired determina si necesita invocar o si ya está en el hilo correcto, no si desea realizar llamadas sincrónicas o asíncronas. Si InvokeRequired es falso, usted (en teoría) ya se está ejecutando en el hilo de la interfaz de usuario y simplemente puede realizar acciones síncronas directamente (o aún BeginInvoke si necesita desactivarlas de forma asincrónica). Esto también significa que no puede usar Invoke si InvokeRequired es falso, porque no hay forma de que el bucle de mensajes en el hilo actual continúe. Ese es un gran problema con su código anterior, pero no necesariamente el error que está informando. Usted puede realmente utilizar BeginInvoke en cualquier caso, si tiene cuidado con la invocación recursiva, y así sucesivamente.

Sin embargo, no puede usar ninguna de ellas sin un asa de ventana. Si el Form/Control se ha instanciado pero no se ha inicializado (es decir, antes de que se muestre por primera vez), es posible que aún no tenga un identificador. Y el identificador se elimina mediante Dispose(), como después de cerrar el formulario. En cualquier caso, InvokeRequired devolverá falso porque no es posible invocar sin un identificador. Puede marcar IsDisposed, y también hay una propiedad IsHandleCreated que prueba más específicamente si existe el identificador. Por lo general, si IsDisposed es verdadero (o si IsHandleCreated es falso), quiere ingresar en un caso especial, como simplemente descartar la acción como no aplicable.

Por lo tanto, el código que desea es probablemente más como:

if (IsHandleCreated) 
{ 
    // Always asynchronous, even on the UI thread already. (Don't let it loop back here!) 
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
    return; // Fired-off asynchronously; let the current thread continue. 

    // WriteToForm will be called on the UI thread at some point in the near future. 
} 
else 
{ 
    // Handle the error case, or do nothing. 
} 

O tal vez:

if (IsHandleCreated) 
{ 
    // Always synchronous. (But you must watch out for cross-threading deadlocks!) 
    if (InvokeRequired) 
     Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
    else 
     WriteToForm(finished, numCount); // Call the method (or delegate) directly. 

    // Execution continues from here only once WriteToForm has completed and returned. 
} 
else 
{ 
    // Handle the error case, or do nothing. 
} 
+0

thx por respuesta. – senzacionale

+0

esto también es útil para las tareas asíncronas que invocan métodos en el hilo principal de la interfaz de usuario, pero el formulario se descarta antes de llamar a la invocación. –

7

Esto sucederá típicamente en escenarios multiproceso donde alguna fuente externa (tal vez un NetworkStream) envía datos a un formulario antes de que el formulario se haya inicializado correctamente.

El mensaje también puede aparecer después de eliminar un formulario.

Puede consultar IsHandleCreated para ver si ya se creó un formulario, pero debe poner todo en el correcto manejo de errores, ya que la declaración Invoke puede arrojar una excepción si intenta actualizar su formulario mientras se cierra la aplicación.

2

Si va a utilizar un control desde otro hilo antes de mostrar el control o haciendo otras cosas con el control, considere forzar la creación de su identificador dentro del constructor. Esto se hace usando la función CreateHandle. En un proyecto de subprocesos múltiples, donde la lógica de "controlador" no está en un WinForm, esta función es fundamental para evitar este tipo de errores.

1

Probablemente está llamando a esto en el constructor del formulario, en ese momento el identificador de la ventana del sistema subyacente aún no existe.

5

aquí es mi respuesta

Digamos que desea escribir "Hola Mundo" a un cuadro de texto. Entonces, si usa "Ishandlecreated", su operación no ocurrirá si los manipuladores aún no se han creado. Por lo tanto, debe obligarse a CreateHandlers si aún no se ha creado.

Aquí está mi código

if (!IsHandleCreated) 
    this.CreateControl(); 

this.Invoke((MethodInvoker)delegate 
{ 
    cmbEmail.Text = null; 

}); 
Cuestiones relacionadas