2011-05-03 62 views
8

Actualmente estoy trabajando con WinForms (en C#) y tengo que ejecutar la aplicación en segundo plano. Para este propósito estoy usando asincrónico. Cuando ejecuto la aplicación muestra una excepción comoResuelva una excepción de cross-threading en WinForms

"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."

¿Cómo puedo resolver este error?

+0

posible duplicado de [Ayúdame con que desgarre?] (Http://stackoverflow.com/questions/337165/help-me-with-that-crossthread) – jgauffin

+0

posible duplicado de [¿Por qué recibo este error: "Operación entre subprocesos no válida: Control lbFolders accedido desde un hilo que no sea el hilo en el que se creó."?] (http://stackoverflow.com/questions/244591/why-am-i-getting-this -errorcross-thread-operation-not-valid-control-lbfolders) –

Respuesta

9

Al hacer llamadas de método a un control, si la persona que llama está en un hilo diferente al que se creó en el control, debe llamar usando Control.Invoke. Aquí está un ejemplo de código:

// you can define a delegate with the signature you want 
public delegate void UpdateControlsDelegate(); 

public void SomeMethod() 
{ 
    //this method is executed by the background worker 
    InvokeUpdateControls(); 
} 

public void InvokeUpdateControls() 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new UpdateControlsDelegate(UpdateControls)); 
    } 
    else 
    { 
     UpdateControls(); 
    } 
} 

private void UpdateControls() 
{ 
    // update your controls here 
} 

espero que ayude.

+0

Hola, gracias por darme respuesta, estoy tratando de proporcionar el código, en realidad llamo al thred en el evento button_click ... pero siempre voy a la parte else ... ..no ingrese esto si (this.InvokeRequired) { this.Invoke (nuevo PerformSomeActionDelegate (MyAction)); } – Victor

+0

@Victor: Eso significa que Invoke no es necesario en este momento. Asegúrese de que todo el código que se ejecuta en el hilo realiza llamadas de "seguridad" (Invocar) para actualizar los controles de su formulario. –

+0

no puedo obtener Daniel puedo publicar mi código aquí .. – Victor

3

La mayoría de las veces, la mejor forma de hacer este tipo de cosas con WinForms es usar BackgroundWorker, que ejecutará su trabajo en una cadena de fondo, pero le proporcionará una forma limpia y agradable de informar el estado a la IU.

En una gran cantidad de todos los días de programación .NET, crear explícitamente hilos o llamando .Invoke es una señal de que no está utilizando el marco de su máximo (por supuesto, hay un montón de razones legítimas para hacer de bajo nivel cosas también, es solo que son menos comunes que la gente a veces se da cuenta).

+0

Gracias por dar una respuesta. Estoy usando este código de fondo (lo que está dando en el enlace de arriba) en mi aplicación. Pero esto muestra un error ... – Victor

+2

@Victor - debes usar .Invocar (ver ejemplos de otras personas), O utilice el método BackgroundWorker.ReportProgress (y el evento ProgressChanged que genera) para acceder al formulario. Si estuviese utilizando BackgroundWorker, siempre estaría a favor de ReportProgress a través de las llamadas a Invoke directas. –

2

Debe verificar si se requiere Invocar para el control que está tratando de actualizar. Algo como esto:

Action<Control, string> setterCallback = (toSet, text) => toSet.Text = text; 

void SetControlText(Control toSet, string text) { 
    if (this.InvokeRequired) { 
    this.Invoke(setterCallback, toSet, text); 
    } 
    else { 
    setterCallback(toSet, text); 
    } 
} 
1

Un patrón le puede resultar útil es hacer una verificación en la parte superior de las funciones que interactúan con la interfaz gráfica de usuario para ver si se está ejecutando en la secuencia correcta o no y tienen la función de invocar propio si es requerido. De esta manera:

public delegate void InvocationDelegate(); 

    public void DoGuiStuff(){ 
     if (someControl.InvokeRequired){ 
     someControl.Invoke(InvocationDelegate(DoGuiStuff)); 
     return; 
     } 

     //GUI manipulation here 
    } 

El uso de este patrón - si usted está en el hilo correcto cuando se llama al método que no invoca en sí, pero si usted está en un subproceso diferente que invocará a sí mismo y luego regresar (por lo la lógica de manipulación de la GUI solo se llama una vez en ambos sentidos).

0

actualizados de Invoke para comenzar Invoke

// you can define a delegate with the signature you want 
public delegate void UpdateControlsDelegate(); 

public void SomeMethod() 
{ 
    //this method is executed by the background worker 
    InvokeUpdateControls(); 
} 

public void InvokeUpdateControls() 
{ 
    if (this.InvokeRequired) 
    { 
     this.BeginInvoke(new UpdateControlsDelegate(UpdateControls)); 
    } 
    else 
    { 
     UpdateControls(); 
    } 
} 

private void UpdateControls() 
{ 
    // update your controls here 
} 
+0

Hola Pankaj ya he intentado este código pero el invokerequired siempre es falso cuando es verdadero ... llamo a la invocación requerida en mi evento de clic de botón ..... – Victor

+0

reemplace esto con su botón y vuelva a verificar. – Pankaj

+0

escribí código como este void privado btnsiteranks_Click_1 (remitente del objeto, EventArgs e) { InvokeUpdateControls(); } InvokeUpdateControls public void() { si (this.InvokeRequired) { this.BeginInvoke (nueva PerformSomeActionDelegate (Geturls)); } else { Geturls(); } } – Victor

0

Los cambios de interfaz de usuario se puede hacer con Control.Invoke() métodos, esta excepción hilo transversal puede ser resuelto mediante el siguiente fragmento de código.

void UpdateWorker() 
{ 
    //Here ddUser is the user control 
    //Action to be performed should be called within { } as like below code 
    if (this.ddUser.InvokeRequired) 
     ddUser.Invoke(new MethodInvoker(() => { ddUser.Size = new Size(100, 100); })); 
} 
Cuestiones relacionadas