要实现我们讨论的行为,显然需要实现 Controller 类。为了使此架构能够在多数方案中应用,我们还会定义一些正式接口,可以由 Controller 在与 UI(或客户端)和辅助线程交互时使用。
通过为客户端和辅助线程定义正式接口,我们可以在不同的情况下使用相同的 Controller 对象,还可以根据需要使用不同的 UI 要求和不同的 Worker 对象。
下面的 UML 类图表显示了 Controller 类以及 IClient 和 IWorker 接口。它还显示了 IController 接口,辅助代码将通过它与 Controller 对象交互。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com)图 5:Controller 和相关接口的类图表
IClient 接口定义的方法将由 Controller 对象调用,用于向客户端 UI 通报 Worker 的开始时间、结束时间和任何中间状态消息。它还包含一个指示辅助代码失败的方法。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com)多数情况下,我们可以将这些方法作为由 Controller 对象发出而由 UI 处理的事件来实现。但是,从辅助线程发出事件然后由 UI 线程正确处理并非易事,因而我们将其作为一组方法来进行实现。
使控制器代码(在辅助代码上运行)调用 UI 中的这些方法并由 UI 线程进行处理,这样相对要简单得多。
同样,IWorker 接口定义了由 Controller 对象调用的、使其可以与辅助代码交互的方法。使用 Initialize 方法可以为辅助代码提供对 Controller 对象的引用,而使用 Start 方法可以启动后台线程上的操作。
由于线程的工作方式,Start 方法无法包含任何参数。启动新线程时,必须将不接受任何参数的方法的地址传递给线程。
请注意,IWorker 接口中不存在 Cancel 或 Stop 方法。我们不能强制辅助代码停止,同时也没有这个必要;但是辅助代码可以使用 IController 接口询问 Controller 对象是否存在取消请求。
IController 接口定义了辅助代码可以在 Controller 对象上调用的方法。它允许辅助代码检查 Running 标志。如果存在取消请求,Running 标志即为 False。它还允许辅助代码在工作完成或无法完成时告诉 Controller,并允许使用状态消息和完成百分比值(0 到 100 之间的 Integer)更新 Controller。
最后我们定义了 Controller 对象。该对象中包含一些可以被 UI 代码调用的方法。其中包括 Start 方法,该方法可以通过为 Controller 对象提供对 Worker 对象的引用来启动后台操作。还包括 Cancel 方法,该方法用于请求取消操作。UI 也可以检查 Running 属性,查看是否存在取消请求;还可以检查 Percent 属性,查看任务完成的百分比。
Controller 类中包含的 constructor 方法接受 IClient 作为参数,还允许 UI 为 Controller 提供对窗体(用于处理 Worker 中的显示消息)的引用。
为了实现一系列动画点来显示线程的活动,我们将创建一个简单 Windows 窗体控件,该控件使用计时器以更改一系列 PictureBox 控件中的颜色。
实现方案我们将在 Class Library(类库)项目中实现此架构,使其可用于需要运行后台进程的应用程序。
打开 Visual Studio .NET,然后创建一个名为 Background 的新 Class Library(类库)应用程序。由于此库将包含 Windows 窗体控件和窗体,因此需要使用 Add References(添加引用)对话框引用 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 的类,代码如下:
<