我遇到了从非UI线程中引发事件的一些问题,因为我不希望在Form1中添加到线程的每个事件处理程序上处理If me.invokerequired。
我确信我已经在某处阅读了如何使用委托事件(在SO上),但我无法找到它。
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
答案 0 :(得分:2)
您从Control派生了您的班级。有点不寻常,但如果控件实际托管在表单上,您可以使用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():
Private mHost As Form
Public Sub New(ByVal host As Form)
mHost = host
End Sub
并使用mHost.Invoke()。或者BeginInvoke()。
本书的最后一个技巧是使用主启动表单作为同步对象。这不是完全安全的,但在99%的情况下有效:
Dim main As Form = Application.OpenForms(0)
main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)
请注意,WF中存在一个错误,阻止OpenForms()在动态重新创建时准确跟踪打开的表单。
答案 1 :(得分:1)
如果你想简化所有这些,可以使用一个名为BackgroundWorker的类来处理GUI线程编组。