C# 从线程安全地引发事件

C# 从线程安全地引发事件,c#,vb.net,multithreading,C#,Vb.net,Multithreading,对于从非UI线程引发的事件,我遇到了一些问题,因为我不希望必须在Form1中添加到线程的每个事件处理程序上处理If me.invokererequired 我确信我在某个地方读过如何使用委托事件(如此),但我找不到它 Public Class Form1 Private WithEvents _to As New ThreadedOperation Private Sub Button_Click(ByVal sender As System.Object, ByVal e

对于从非UI线程引发的事件,我遇到了一些问题,因为我不希望必须在Form1中添加到线程的每个事件处理程序上处理If me.invokererequired

我确信我在某个地方读过如何使用委托事件(如此),但我找不到它

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

您从控件派生了类。有点不寻常,但如果控件实际上托管在表单上,则可以使用Me.Invoke()封送调用。例如:

  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
如果该类对象实际上未托管在表单上,则需要传递对该表单的引用,以便它可以调用Invoke():

并使用mHost.Invoke()。或开始唤醒()

本书的最后一个技巧是使用主启动窗体作为同步对象。这并不完全安全,但在99%的情况下都有效:

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

请注意,WF中存在一个bug,它阻止OpenForms()在动态重新创建打开的表单时准确跟踪它们。

如果您想简化所有这些,可以使用一个名为BackgroundWorker的类来处理GUI线程封送。

是的,我非常了解/使用后台工作程序,但是,这个组件需要对其线程有更大的控制。我接受了第二个建议,即传递主机控件(我传递的是控件对象,而不是窗体)。谢谢
  Dim main As Form = Application.OpenForms(0)
  main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)