2008-11-15 7 views
1

Je rencontre des problèmes avec les événements en cours d'augmentation du thread non-UI, en ce sens que je ne souhaite pas gérer le if me.invokerequired sur chaque gestionnaire d'événements ajouté au thread dans Form1.Obtention d'événements à partir d'un thread en toute sécurité

Je suis sûr d'avoir lu quelque part comment utiliser un événement délégué (sur SO) mais je suis incapable de le trouver.

Public Class Form1 

    Private WithEvents _to As New ThreadedOperation 

    Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button.Click 
     _to.start() 
    End Sub 

    Private Sub _to_SomthingHappend(ByVal result As Integer) Handles _to.SomthingHappend 
     TextBox.Text = result.ToString //cross thread exception here 
    End Sub 

End Class 

Public Class ThreadedOperation 

    Public Event SomthingHappend(ByVal result As Integer) 
    Private _thread As Threading.Thread 

    Public Sub start() 
     If _thread Is Nothing Then 
      _thread = New Threading.Thread(AddressOf Work) 
     End If 
     _thread.Start() 
    End Sub 

    Private Sub Work() 
     For i As Integer = 0 To 10 
      RaiseEvent SomthingHappend(i) 
      Threading.Thread.Sleep(500) 
     Next 
    End Sub 

End Class 

Répondre

2

Vous avez dérivé votre classe de Control. Un peu inhabituel, mais si le contrôle est réellement hébergé sur un formulaire, vous pouvez utiliser Me.Invoke() pour rassembler l'appel. Par exemple:

Private Delegate Sub SomethingHappenedDelegate(ByVal result As Integer) 

    Private Sub Work() 
    For i As Integer = 0 To 10 
     Me.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i) 
     Threading.Thread.Sleep(500) 
    Next 
    End Sub 

    Private Sub SomethingHappenedThreadSafe(ByVal result As Integer) 
    RaiseEvent SomthingHappend(result) 
    End Sub 

Si cet objet de classe n'est pas réellement hébergé sur un formulaire, vous aurez besoin de passer une référence à la forme de sorte qu'il peut appeler Invoke():

Private mHost As Form 

    Public Sub New(ByVal host As Form) 
    mHost = host 
    End Sub 

et l'utilisation mHost.Invoke(). Ou BeginInvoke().

La dernière astuce du livre consiste à utiliser votre formulaire de démarrage principal en tant qu'objet de synchronisation. Ce n'est pas tout à fait sûr, mais fonctionne dans 99% des cas:

Dim main As Form = Application.OpenForms(0) 
    main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i) 

Prenez garde qu'il ya un bogue dans WF qui empêche OpenForms() de suivre précisément les formes ouvertes quand ils sont dynamiquement recréés.

+0

Je suis allé avec la deuxième suggestion, passant le contrôle de l'hôte (je passe dans un objet de contrôle plutôt que d'un formulaire si). merci – Pondidum

1

Si vous souhaitez simplifier tout cela, il existe une classe appelée BackgroundWorker qui gère le marshaling de thread graphique pour vous.

+0

Ouais, je connais/j'utilise beaucoup le Background Worker, ce composant doit cependant avoir un plus grand contrôle sur ses thread (s) – Pondidum

Questions connexes