问题描述
我在从非UI线程引发事件时遇到一些问题,因为我不想处理在Form1中添加到线程的每个事件处理程序上的If me.invokerequired.
I am having some problems with events being raised from the non-UI thread, in that i dont wish to have to handle the If me.invokerequired on every event handler added to the thread in Form1.
我确定我已经在某处阅读了如何使用委托事件,但是我找不到它.
I am sure i have read somewhere how to use a delegate event (on SO) but i am unable to find it.
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
推荐答案
您从Control派生了您的课程.有点不寻常,但是如果控件实际上托管在窗体上,则可以使用Me.Invoke()封送调用.例如:
You derived your class from Control. A bit unusual, but if the control is actually hosted on a form, you can use Me.Invoke() to marshal the call. For example:
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():
If this class object is not actually hosted on a form, you'll need to pass a reference to the form so it can call Invoke():
Private mHost As Form
Public Sub New(ByVal host As Form)
mHost = host
End Sub
并使用mHost.Invoke().或BeginInvoke().
and use mHost.Invoke(). Or BeginInvoke().
这本书的最后一个技巧是将您的主要启动表单用作同步对象.这并不完全安全,但可以在99%的情况下起作用:
The last trick in the book is to use your main startup form as the synchronization object. That's not completely safe but works in 99% of the case:
Dim main As Form = Application.OpenForms(0)
main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)
请注意,WF中存在一个错误,该错误会阻止OpenForms()在动态重新创建打开的表单时准确地跟踪它们.
Beware that there's a bug in WF that prevents OpenForms() from accurately tracking open forms when they get dynamically recreated.
这篇关于安全地从线程引发事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!