una traves todos thread subprocesos subproceso requiere que para los llamó llamar interfaz hilos función form example evaluación ejemplo ejecuten diferente controles como checkforillegalcrossthreadcalls aplicación aplanó winforms multithreading

winforms - traves - la evaluación de la función requiere que se ejecuten todos los subprocesos



Problema de subprocesos de Winforms, el segundo subproceso no puede tener acceso a los controles de las 1ras formas principales (10)

Comprobar la invocación requerida

Tengo una aplicación de winforms, el problema tiene que ver con el enhebrado. Desde que estoy llamando a ''MyCustomCode () que crea un nuevo hilo, y llama al método'' SomeMethod () ''que luego accede a MessageBox.Show (...).

El problema tiene que ver con el subprocesamiento, ya que el subproceso recién creado está intentando acceder a un control que se creó en otro subproceso.

Estoy obteniendo el error:

Operación entre subprocesos no válida: Control ''TestForm'' accedido desde un subproceso que no sea el subproceso en el que se creó.

public TestForm() { InitializeComponent(); // custom code // MyCustomCode(); } public void SomeMethod() { // ***** This causes an error **** MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } private void InitializeAutoUpdater() { // Seperate thread is spun to keep polling for updates ThreadStart ts = new ThreadStart(SomeMethod); pollThread = new Thread(ts); pollThread.Start(); }

Actualizar

Si miras este ejemplo http://www.codeproject.com/KB/cs/vanillaupdaterblock.aspx , el método CheckAndUpdate llama a MessageBox.Show (..) ese es mi problema. ¡Hubiera pensado que el código estaba listo para funcionar!

Lo gracioso es que este código estaba funcionando bien el viernes ???


La regla número uno cuando multi-threading es absolutamente no puede tocar la interfaz de usuario de subprocesos de trabajo. Hay muchas maneras de implementar multi-threading y es muy difícil hacerlo "correcto".

Aquí hay un artículo sucinto que debería ayudarte: actualizar la interfaz de usuario de un subproceso secundario

Y aquí hay un extenso artículo que analiza el enhebrado en profundidad: Multi-threading en .NET


No puede acceder a los elementos de la interfaz de usuario de varios subprocesos.

Una forma de resolver esto es llamar al método Invoke de un control con un delegado a la función que usa los elementos UI (como el cuadro de mensaje). Algo así como:

public delegate void InvokeDelegate(); public void SomeMethod() { button1.Invoke((InvokeDelegate)doUIStuff); } void doUIStuff() { MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); }


Para mantener las cosas simples, puede considerar usar la clase BackGroundWorker . Esta clase proporcionará un marco para manejar sus eventos de subprocesamiento y notificación de progreso. Su subproceso de ui manejará el evento de progreso y mostrará el mensaje de error que devuelve.


para evitar excepciones entre hilos (InvalidOperationException), aquí está el patrón de código:

protected delegate void someGuiFunctionDelegate(int iParam); protected void someGuiFunction(int iParam) { if (this.InvokeRequired) { someGuiFunctionDelegate dlg = new someGuiFunctionDelegate(this.someGuiFunction); this.Invoke(dlg, new object[] { iParam }); return; } //do something with the GUI control here }

Estoy de acuerdo en que esto es molesto, pero es un hecho del hecho de que los controles GUI de Windows no son seguros para subprocesos. La excepción se puede desactivar con una bandera en algún lugar u otro, pero no lo haga, ya que puede provocar errores extremadamente difíciles de encontrar.


NO deberías usar BeginInvoke, debes usar Invoke, luego, una vez que entiendas eso, puedes considerar usar BeginInvoke si realmente lo necesitas.



Me gusta especialmente una llamada recursiva.

public delegate void InvokeDelegate(string errMessage); public void SomeMethod() { doUIStuff("my error message"); } void doUIStuff(string errMessage) { if (button1.InvokeRequired) button1.Invoke((InvokeDelegate)doUIStuff(errMessage)); else { MessageBox.Show(this, ex.Message, errMessage, MessageBoxButtons.OK, MessageBoxIcon.Error ); } }


Sé que esta es una publicación más antigua, pero recientemente encontré una solución elegante para este problema usando genéricos y métodos de extensión. Esta es una combinación de los trabajos de los autores y algunos comentarios.

Un método genérico para el acceso de formas cruzadas de Winforms

http://www.codeproject.com/KB/cs/GenericCrossThread.aspx

public static void Manipulate<T>(this T control, Action<T> action) where T : Control { if (control.InvokeRequired) { control.Invoke(new Action<T, Action<T>>(Manipulate), new object[] { control, action }); } else { action(control); } }

Esto se puede llamar de la siguiente manera, por simplicidad utilicé una etiqueta.

someLabel.Manipulate(lbl => lbl.Text = "Something");


''******************************************************************* '' Get a new processor and fire it off on a new thread. ''******************************************************************* fpProc = New Processor(confTable, paramFile, keyCount) AddHandler fpProc.LogEntry, AddressOf LogEntry_Handler Dim myThread As System.Threading.Thread = New System.Threading.Thread(AddressOf fpProc.ProcessEntry) myThread.Start()

Luego, en la aplicación principal tienes:

''************************************************************************* '' Sub: LogEntry_Handler() '' Author: Ron Savage '' Date: 08/29/2007 '' '' This routine handles the LogEntry events raised by the Processor class '' running in a thread. ''************************************************************************* Private Sub LogEntry_Handler(ByVal logLevel As Integer, ByVal logMsg As String) Handles fProc.LogEntry writeLogMessage(logMsg); End Sub

Eso es lo que hago.