web-dev-qa-db-fra.com

Crossthread opération non valide ... - VB.NET

J'utilise vb.net et, dans mon programme, le message d'erreur '' Crossthread Operation Not Valid '' s'affiche lorsque j'exécute le travail de fond qui rendra cette zone de texte activée. Mon sous-traitant principal commence par activer la valeur false, puis, une fois le travail d'arrière-plan exécuté, il le rendra à nouveau puis à la sortie. Pourquoi ça me donne une erreur? FYI: Il y a plus de code à cela mais je ne veux pas le rendre plus déroutant ...

Voici la trace de la pile:

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)

et voici le message d'erreur exact:

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

Quelqu'un peut-il m'aider s'il vous plaît! 

Merci,

KEvin

13
lab12

L'objectif de la classe BackgroundWorker est d'effectuer un travail sur un thread non-GUI tant que l'interface graphique reste sensible. Sauf si vous définissez Control.CheckForIllegalCrossThreadCalls sur false (ce que vous ne devriez pas faire), ou utilisez Invoke comme suggéré dans les autres réponses (ce que je ne recommanderais pas non plus), vous obtiendrez une exception d'opération de groupe croisé illégale.

Si vous voulez que les "commandes" liées à l'interface graphique se produisent pendant que votre BackgroundWorker est en cours d'exécution, je vous recommanderais généralement d'utiliser la méthode BackgroundWorker.ReportProgress et d'associer un gestionnaire approprié à l'événement BackgroundWorker.ProgressChanged. Si vous souhaitez que quelque chose apparaisse sur l'interface graphique une fois que BackgroundWorker est terminé , attachez simplement votre gestionnaire pour mettre à jour l'interface graphique à l'événement BackgroundWorker.RunWorkerCompleted.

20
Dan Tao

Tapez le code suivant dans le Form1_Load (ou quel que soit votre formulaire):

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

Il corrige tous les problèmes liés aux opérations inter-thread bloquées.

11
alex

Où définissez-vous exactement la propriété Enabled? Si vous le faites dans le gestionnaire d'événements DoWork, ce code s'exécute sur un thread différent de celui sur lequel le bouton a été créé, ce qui devrait donner l'exception que vous rencontrez. Pour résoudre ce problème, vous devez utiliser BeginInvoke. Pour plus de commodité, il pourrait être intégré à une méthode, comme suit:

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

Maintenant, vous pouvez appeler cette méthode en toute sécurité pour activer ou désactiver n'importe quel contrôle depuis n'importe quel thread:

SetControlEnabled(someButton, False)
10
Fredrik Mörk

Une meilleure façon de procéder dans VB.NET consiste à utiliser une variable Extension, ce qui donne un très beau code pour les appels de contrôle d'interface graphique multithreading.

Ajoutez simplement cette ligne de code à n’importe quel module que vous avez.

<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

Vous pouvez maintenant écrire du code de contrôle multithread ne comportant qu'une ligne pour tout appel de contrôle.

Comme cela, disons que vous voulez effacer une ComboBox et qu'elle s'appelle à partir de threads ou sans threads, vous pouvez simplement utiliser le faire maintenant

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

Voulez-vous ajouter quelque chose après l'avoir effacé?

cboServerList.Invoke(Sub() cboServerList.Items.Add("Hello World"))
8
SSpoke

Vous ne pouvez pas définir directement la propriété d'un contrôle qui se trouve sur le thread d'interface utilisateur à partir d'un autre thread. Cela peut être fait cependant, voici un exemple tiré 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
2
jac

Votre Form_Load () pls écrit ci-dessous la partie de code. Tous vos problèmes seront résolus.

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

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
1
AlperDiktas

Suggérez d'utiliser AutomationPeer.

Par exemple, ci-dessous, le code appelle le bouton Exécuter lorsque j'appuie sur la touche F5. De même, si vous souhaitez qu'un thread ou un travailleur en arrière-plan appelle un événement ou une fonction, vous pouvez utiliser Automation Peer. Dans votre cas, au lieu du bouton (que j'ai utilisé ici), vous pouvez utiliser une zone de texte avec sa propriété appropriée à appeler.

'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

Cordialement RV

0
Venkat