2010-02-10 23 views
11

Estoy utilizando vb.net, y en mi programa aparece el error 'crossthread operation no válido' cuando ejecuto mi backgroundworker que hará que este cuadro de texto habilitado sea verdadero. Mi sub principal primero convertirá el habilitado en falso, y cuando el backgroundworker se ejecute, lo volverá verdadero y luego saldrá. ¿Por qué me da un error? FYI: hay más código para esto, pero yo no quiero hacerlo más confuso ...Operación Crossthread no válida ... - VB.NET

Aquí es el seguimiento de la pila:

at System.Windows.Forms.Control.get_Handle() 
    at System.Windows.Forms.Control.OnEnabledChanged(EventArgs e) 
    at System.Windows.Forms.Control.set_Enabled(Boolean value) 
    at Helium.Form1.BackgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in C:\Users\Kevin\documents\visual studio 2010\Projects\Helium\Helium\Form1.vb:line 167 
    at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e) 
    at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument) 

y aquí está el mensaje de error exacto:

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

¿Alguien puede ayudarme por favor!

Gracias,

Kevin

+0

yo creo que el mensaje de error era bastante auto-explicativo. –

Respuesta

16

El propósito de la clase BackgroundWorker es realizar el trabajo en un subproceso no GUI mientras la GUI sigue siendo receptiva. A menos que establezca Control.CheckForIllegalCrossThreadCalls en false (que no debe hacer), o use Invoke como se sugiere en las otras respuestas (que tampoco recomendaría), obtendrá una excepción de operación cruzada ilegal.

Si desea GUI-relacionados "cosas" que suceda mientras su BackgroundWorker se está ejecutando, yo generalmente recomiendo usar el método BackgroundWorker.ReportProgress y adjuntando un controlador adecuado para el evento BackgroundWorker.ProgressChanged. Si desea que suceda algo en la GUI una vez que BackgroundWorker es terminó, simplemente conecte su controlador para actualizar la GUI al evento BackgroundWorker.RunWorkerCompleted.

+0

+1. El uso del 'backgroundworker.reportprogress' me ayudó a actualizar mi GUI mientras el hilo estaba en ejecución. – Codemunkeee

2

No se puede establecer la propiedad de un control que está en el hilo de interfaz de usuario desde otro hilo directamente. Sin embargo, se puede hacer, aquí hay un ejemplo de msdn.

Private Sub SetText(ByVal [text] As String) 

    ' InvokeRequired required compares the thread ID of the' 
    ' calling thread to the thread ID of the creating thread.' 
    ' If these threads are different, it returns true.' 
    If Me.textBox1.InvokeRequired Then 
     Dim d As New SetTextCallback(AddressOf SetText) 
     Me.Invoke(d, New Object() {[text]}) 
    Else 
     Me.textBox1.Text = [text] 
    End If 
End Sub 
+0

Entonces, ¿dónde debería poner la parte textbox1.enabled = true? – lab12

10

¿Dónde se establece exactamente la propiedad Enabled? Si lo hace dentro del controlador de eventos DoWork, este código se ejecuta en un subproceso diferente al que se creó en el botón, que debe dar la excepción que experimenta. Para evitar esto, debe usar BeginInvoke. Para mayor comodidad podría ser envuelto en un método, así:

Private Sub SetControlEnabled(ByVal ctl As Control, ByVal enabled As Boolean) 
    If ctl.InvokeRequired Then 
     ctl.BeginInvoke(New Action(Of Control, Boolean)(AddressOf SetControlEnabled), ctl, enabled) 
    Else 
     ctl.Enabled = enabled 
    End If 
End Sub 

Ahora puede llamar de forma segura que el método para activar o desactivar cualquier control desde cualquier hilo:

SetControlEnabled(someButton, False) 
2

Su Form_Load() pls escribe a continuación parte del código. Todos sus problemas serán resueltos.

'## crossed-thread parts will not be controlled by this option... 

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False 
11

Escriba el siguiente código en la sub Form1_Load (o lo que su forma es):

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False 

Se soluciona todos los problemas con las operaciones entre subprocesos bloqueados.

+0

Tenga en cuenta que esta respuesta es * mala *, como se explica en [¿Es seguro simplemente establecer CheckForIllegalCrossThreadCalls en falso para evitar errores cruzados durante la depuración?] (Http://stackoverflow.com/questions/13345091/is-it-safe -just-to-set-checkforillegalcrossthreadcalls-to-false-to-avoid-cross-t). ** No lo use y en su lugar resuelva los problemas con su código (es decir, cree delegados adecuados). ** – cybermonkey

5

Mejor manera de esto en VB.NET es utilizar un Extension que hace un código muy atractivo para el cruce de las llamadas de control de GUI.

Simplemente agregue esta línea de código a cualquier Módulo que tenga.

<System.Runtime.CompilerServices.Extension()> _ 
Public Sub Invoke(ByVal control As Control, ByVal action As Action) 
    If control.InvokeRequired Then 
     control.Invoke(New MethodInvoker(Sub() action()), Nothing) 
    Else 
     action.Invoke() 
    End If 
End Sub 

Ahora puede escribir el código de Control de hilo cruzado que tiene solo 1 línea de longitud para cualquier llamada de control.

De esta manera, digamos que usted desea borrar un ComboBox y se llama a partir de hilos o sin hilos, puedes usar hacerlo ahora

cboServerList.Invoke(Sub() cboServerList.Items.Clear()) 

desea agregar algo después de que lo elimine?

cboServerList.Invoke(Sub() cboServerList.Items.Add("Hello World")) 
0

Sugerir uso AutomationPeer.

Por ejemplo, debajo de las llamadas de código Ejecutar el botón cuando presiono la tecla F5. De forma similar, si quiere un hilo o un trabajador de fondo para llamar a un evento o función, puede usar Automation Peer. En su caso, en lugar de botón (que utilicé aquí), puede usar el cuadro de texto con su propiedad apropiada para invocar.

'Button name=btnExecute 

'Imports System.Windows.Automation.Peers 

'Imports System.Windows.Automation.Provider 

If e.Key = Key.F5 Then 

    Dim peer As New ButtonAutomationPeer(btnExecute) 

    Dim invokeProv As IInvokeProvider = TryCast(peer.GetPattern(PatternInterface.Invoke), IInvokeProvider) 

    invokeProv.Invoke() 

End If 

Saludos RV

0
CheckForIllegalCrossThreadCalls = False 
+0

Agregue alguna explicación adicional. – rghome

Cuestiones relacionadas