典型情况下这些并不麻烦。其结果是Invoke方法触发一个进程,通过该进程窗体终止在自己的UI线程上运行的方法,这正是我们的设计目标。
同样这些代码写入一个区域(Region),可以使它们在worker线程中被调用时比较清晰。
| #Region " Code called from the worker thread " '从worker线程调用来更新显示 '它用状态信息触发了一个向UI的方法调用 '该调用在UI线程上作出 Private Sub Display(ByVal Text As String) _ Implements IController.Display Dim disp As New DisplayDelegate( _ AddressOf CType(mClient, IClient).Display) Dim ar() As Object = {Text} '调用UI线程的客户窗体来更新显示 mClient.BeginInvoke(disp, ar) End Sub '从worker线程调用用于显示失败。 '它用exception对象触发了一个向UI的方法调用 '该调用在UI线程上作出 Private Sub Failed(ByVal e As Exception) _ Implements IController.Failed Dim disp As New FailedDelegate(_ AddressOf CType(mClient, IClient).Failed) Dim ar() As Object = {e} '调用UI线程上的客户窗体来显示失败 mClient.Invoke(disp, ar) End Sub '从worker线程调用来表明完成百分比 '该值进入Controller,如果需要能在那儿被UI读取 Private Sub SetPercent(ByVal Percent As Integer) _ Implements IController.SetPercent mPercent = Percent End Sub '从worker线程调用来显示已经完成 '传递了一个参数用于显示真的完成了和者"取消"了 '该调用在UI线程中作出 Private Sub Completed(ByVal Cancelled As Boolean) _ Implements IController.Completed mRunning = False Dim comp As New CompletedDelegate( _ AddressOf CType(mClient, IClient).Completed) Dim ar() As Object = {Cancelled} '从UI线程调用客户窗体来显示完成了 mClient.Invoke(comp, ar) End Sub '显示是否仍在运行或者有"取消"请求 '该调用在worker线程上作出,这样worker代码可以看是否应该温和地退出 Private ReadOnly Property Running() As Boolean _ Implements IController.Running Get Return mRunning End Get End Property #End Region Failed和Completed方法使用了窗体的Invoke方法。下面使Failed的代码: Dim disp As New FailedDelegate(_ AddressOf CType(mClient, IClient).Failed) Dim ar() As Object = {e} '从UI线程调用客户窗体来显示失败 mClient.Invoke(disp, ar) |
首先所我们从IClient接口中建立一个委托指向窗体的Failed事件,接着我们声明了一个类型对象数组存放传递给该方法的参数值,最后调用客户窗体的Invoke方法,传递委托指针和参数数组给窗体。
随后窗体在UI线程中使用这些参数调用该方法,它可以安全的运行来更新显示。
这整个过程是同步的,意味着向窗体作调用时工作线程被阻塞。虽然因为错误消息或者完成消息而阻塞工作线程是合适的,但我们不想因为一点点状态显示而阻塞它。
为了避免在状态显示时的阻塞,Display方法用BeginInvoke代替了Invoke. BeginInvoke促成窗体上的方法调用异步完成,这样工作线程能保持运行而不需要等待窗体显示方法的完成。
| Dim disp As New DisplayDelegate( _ AddressOf CType(mClient, IClient).Display) Dim ar() As Object = {Text} '调用UI线程上的客户窗体来更新显示 mClient.BeginInvoke(disp, ar) |
在这种情况下使用BeginInvoke通过避免阻塞保持了工作线程尽可能地高效率运行。
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] 下一页