另外,在Components页上有一个不同的Timer控件。这是个多线程时钟。换句话说,它在后台线程上建立Elapsed事件,不同于UI线程上的Windows窗体时钟。在建立UI时这明显达不到目标,因为Elapsed事件中的代码明显不能直接与UI交互。
现在向控件中添加下列代码:
Private mBoxes As New ArrayList()
Private mCount As Integer
Private Sub ActivityBar_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim index As Integer
If mBoxes.Count = 0 Then
For index = 0 To 6
mBoxes.Add(CreateBox(index))
Next
End If
mCount = 0
End Sub
Private Function CreateBox(ByVal index As Integer) As PictureBox
Dim box As New PictureBox()
With box
SetPosition(box, index)
.BorderStyle = BorderStyle.Fixed3D
.Parent = Me
.Visible = True
End With
Return box
End Function
Private Sub GrayDisplay()
Dim index As Integer
For index = 0 To 6
CType(mBoxes(index), PictureBox).BackColor = Me.BackColor
Next
End Sub
Private Sub SetPosition(ByVal Box As PictureBox, ByVal Index As Integer)
Dim left As Integer = CInt(Me.Width / 2 - 7 * 14 / 2)
Dim top As Integer = CInt(Me.Height / 2 - 5)
With Box
.Height = 10
.Width = 10
.Top = top
.Left = left Index * 14
End With
End Sub
Private Sub tmAnim_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles tmAnim.Tick
CType(mBoxes((mCount 1) Mod 7), PictureBox).BackColor = _
Color.LightGreen
CType(mBoxes(mCount Mod 7), PictureBox).BackColor = Me.BackColor
mCount = 1
If mCount > 6 Then mCount = 0
End Sub
Public Sub Start()
CType(mBoxes(0), PictureBox).BackColor = Color.LightGreen
tmAnim.Enabled = True
End Sub
Public Sub [Stop]()
tmAnim.Enabled = False
GrayDisplay()
End Sub
Private Sub ActivityBar_Resize(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Resize
Dim index As Integer
For index = 0 To mBoxes.Count - 1
SetPosition(CType(mBoxes(index), PictureBox), index)
Next
End Sub
窗体的Load事件建立PictureBox控件并把它们放入一个数组,这样容易循环。Timer控件的Tick事件按次序循环使每个点变为绿色。
这些都由Start事件启动,由Stop事件停止。由于Stop是保留字,该方法的名称加上了方括号:[Stop]。Stop方法不仅停止定时器,而且使所有的方框变为灰色以显示没有当前活动。
建立Worker
前面我们看到了一个简单的Worker类。我们已经定义IWorker接口,现在能利用已经建立的Controller来增强该类。
首先建立Background.dll文件。这一步很重要,如果没有的话,我们在建立测试窗体时,ActivityBar控件不会在Toolbox上出现。
给解决方案添加一个叫bgTest的Windows窗体应用程序项目,将它设置为启动项目。
接着使用Add References 对话框的 Projects页来添加对Background项目的引用。
Public Class Worker Implements IWorker
Private mController As IController
Private mInner As Integer
Private mOuter As Integer
Public Sub New(ByVal InnerSize As Integer, ByVal OuterSize As Integer)
mInner = InnerSize
mOuter = OuterSize
End Sub
'被controller调用,这样可以得到一个controller的指针。
Private Sub Init(ByVal Controller As IController) _
Implements IWorker.Initialize
mController = Controller
End Sub
Private Sub Work()
Implements IWorker.Start
Dim innerIndex As Integer
Dim outerIndex As Integer
Dim value As Double
Try
For outerIndex = 0 To mOuter
If mController.Running Then
mController.Display("Outer loop " & outerIndex & " starting") mController.SetPercent(CInt(outerIndex / mOuter * 100))
Else
'有"取消"请求
mController.Completed(True)
Exit Sub
End If
For innerIndex = 0 To mInner
'在此处作一些cool运算
value = Math.Sqrt(CDbl(innerIndex - outerIndex))
Next
Next
mController.SetPercent(100)
mController.Completed(False)
Catch e As Exception mController.Failed(e) End Try
End Sub
End Class
我们添加了Init方法来执行IWorker.Initialize。Controller调用该方法,这样就有了一个Controller对象的指针。
我们将Work方法改为私有(Private),仅仅用于执行IWorker.Start方法。该方法将在工作线程上运行。
Work方法使用Try..Catch块得到了加强,这样我们能捕捉任何错误并使用Controller的Failed方法将错误返回到UI。
假定代码能运行,在该代码运行时,我们调用Controller对象的Display和SetPercent方法来更新状态和完成百分比。
我们也周期性地检查Controller对象的Running属性来查看是否有"取消"请求。如果有,就停止处理并显示由于有"取消"请求而完成。



