框引用 System.Windows.Forms.dll 和 System.Windows.Drawing.dll。此外,我们可以使用项目的属性对话框在这些项目范围内导入命名空间,如图 6 所示。
图 6:使用项目属性添加项目范围内的命名空间 Imports
此操作完成后,就可以开始编码了。让我们先从创建接口开始。
定义接口
在名为 IClient 的项目中添加一个类,并用以下代码替换其代码:
Public Interface IClient
Sub Start(ByVal Controller As Controller)
Sub Display(ByVal Text As String)
Sub Failed(ByVal e As Exception)
Sub Completed(ByVal Cancelled As Boolean)
End Interface
然后添加名为 IWorker 的类,并用以下代码替换其代码:
Public Interface IWorker
Sub Initialize(ByVal Controller As IController)
Sub Start()
End Interface
最后添加名为 IController 的类,代码如下:
Public Interface IController
ReadOnly Property Running() As Boolean
Sub Display(ByVal Text As String)
Sub SetPercent(ByVal Percent As Integer)
Sub Failed(ByVal e As Exception)
Sub Completed(ByVal Cancelled As Boolean)
End Interface
至此,我们已定义了本文前面所述的所有类图表中的接口。现在可以实现 Controller 类了。
Controller 类
现在,我们可以实现架构的核心,Controller 类。此类中包含的代码可用于启动辅助线程,以及在辅助线程完成之前充当 UI 线程和辅助线程之间的媒介。
在名为 Controller 的项目中添加一个新类。首先添加 Imports,并声明一些变量:
Imports System.Threading
Public Class Controller
Implements IController
Private mWorker As IWorker
Private mClient As Form
Private mRunning As Boolean
Private mPercent As Integer
然后需要声明一些委托。委托是方法的正式指针,而且方法的委托必须具有与方法本身相同的方法签名(参数类型等)。
委托的用途很广。在我们的示例中,委托非常重要,因为委托使我们可以让一个线程调用窗体上的方法,使其在该窗体的 UI 线程上运行。正如 IClient 所定义的那样,要在窗体上调用的三个方法都需要委托:
'' 此委托签名与 IClient.Completed
'' 中的签名相匹配,并用于安全地
'' 调用 UI 线程上的方法
Private Delegate Sub CompletedDelegate(ByVal Cancelled As Boolean)
'' 此委托签名与 IClient.Display
'' 中的签名相匹配,并用于安全地
'' 调用 UI 线程上的方法
Private Delegate Sub DisplayDelegate(ByVal Text As String)
'' 此委托签名与 IClient.Failed
'' 中的签名相匹配,并用于安全地
'' 调用 UI 线程上的方法
Private Delegate Sub FailedDelegate(ByVal e As Exception)
IClient 还定义了 Start 方法,但是该方法可以从 UI 线程调用,因此不需要委托。
下面编写将从 UI 线程调用的代码。代码中包括 constructor 方法、Start 和 Cancel 方法以及 Percent 属性。我将这些内容放入 Region 中,便于大家清楚地了解它们是从 UI 线程调用的。
#Region " 从 UI 线程调用的代码 "
'' 使用客户端初始化 Controller
Public Sub New(ByVal Client As IClient)
mClient = CType(Client, Form)
End Sub
'' 此方法由 UI 调用,因此在
'' UI 线程上运行。此处我们将