示例代碼需要訪問假想的股票報價Web服務。我們在Visual Studio .NET 2003中建立一個Web服務,把它命名為"StockWS"。這個Web服務由一個叫做getPRice()的Web方法組成,該方法只接受一個股票編碼參數:
Public Function getPrice(ByVal stock As String) As Single Return Rnd() * 100 End Function 不管被請求的股票是什么,getPrice()方法都生成一個隨機的價格。它的唯一目標是模擬一個返回特定股票價格的真實的Web服務。 盡管本文使用的是一個成型的Web服務來進行演示的,但是你可以輕易地替換這個Web服務以顯示真正的股票信息。
Private Sub Chart1_Load(ByVal sender As _ System.Object, ByVal e As System.EventArgs) Handles Chart1.Load 'x軸上每隔5點顯示時間 Chart1.AxisX.Step = 5 '每個點之間用5象素間隔 Chart1.AxisX.PiXPerUnit = 5 '使圖表可以滾動 Chart1.Scrollable = True '打開和關閉通訊管道 Chart1.OpenData(COD.Values, 1, COD.Unknown) Chart1.CloseData(COD.Values) End Sub 給當前的窗體添加一個叫做StockQuote的類。StockQuote類調用前面的Web服務并用返回的股票價格來更新圖表。
Public Class StockQuote '組件中圖形的數量 Const NUM_SERIES = 1
Private lastPoint As Integer = 0 Dim stockPrice As Single
Private pStockSymbol As String Private pStockSeries As Integer = 0 Private pChartControl As Chart
WriteOnly Property StockSymbol() Set(ByVal Value) pStockSymbol = Value End Set End Property
WriteOnly Property ChartControl() Set(ByVal Value) pChartControl = Value End Set End Property
Public Sub InvokeWebService() Dim ws As New StockWS.Service1
For i As Integer = 0 To 10000 stockPrice = ws.getPrice(pStockSymbol) pChartControl.Invoke(New _ myDelegate(AddressOf updateChart), New Object() {}) '繼續之前等待1秒鐘 Thread.Sleep(1000) Next End Sub
Public Delegate Sub myDelegate() Public Sub updateChart() pChartControl.OpenData(COD.Values, NUM_SERIES, COD.Unknown) pChartControl.Value(pStockSeries, lastPoint) = stockPrice '顯示x軸上的時間 pChartControl.AxisX.Label(lastPoint) = DateTime.Now.ToShortTimeString lastPoint += 1 pChartControl.CloseData(COD.Values) '把滾動條移到最右邊 pChartControl.AxisX.ScrollPosition = pChartControl.AxisX.ScrollSize End Sub
End Class 你通過StockSymbol屬性把需要的股票編碼傳遞給StockQuote類,并使用ChartControl屬性設置圖表更新。InvokeWebService()方法在循環(示例中設置為10,000)中周期性地調用上面的Web服務。由于這個類會在一個單獨的線程中執行,你必須非常小心以確保自己不會自動地更新某個Windows控件,因為Windows控件并不是線程安全的(thread-safe)。作為代替,你必須使用委托并調用自己希望更新的控件上的Invoke()方法。代碼每秒鐘調用Web服務一次,這是由Thread.Sleep(1000)語句設置的。
Private Sub BTnGetStockQuote1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnGetStockQuote1.Click Dim sq As New StockQuote sq.StockSymbol = cmbStocks1.SelectedItem sq.ChartControl = Chart1 t1 = New Thread(AddressOf sq.InvokeWebService) t1.Start() End Sub 把調用該Web服務的代碼打包為一個類的主要原因是Thread類構造函數只能接受一個ThreadStart委托(啟動線程的方法的委托),不存在可以接受多個參數值的重載的Thread.Start()方法。因此,把多個參數傳遞到一個線程中的唯一途徑是把調用的相關代碼打包為一個類,接著你就可以通過這個類的參數來傳遞參數。
Dim t1, t2 As Thread 示例項目使用計時器控件(Timer,在工具箱中)來顯示第二個線程的狀態信息。把計時器拖放到窗體上,并把它的Interval屬性設置為500,這使該計時器的Tick事件每半秒鐘(500毫秒)調用一次。Tick事件處理程序中的代碼更新了標簽控件lblThreadStatus中的線程狀態信息:
Private Sub Timer1_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Timer1.Tick lblThreadStatus.Text = "Thread state: " & _ t2.ThreadState.ToString End Sub 第二個圖表也使用與第一個圖表相同的初始化代碼:
Private Sub Chart2_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Chart2.Load '在x軸上每5點顯示時間 Chart2.AxisX.Step = 5 '每個點之間用5個象素分隔 Chart2.AxisX.PixPerUnit = 5 '使圖表可以滾動 Chart2.Scrollable = True '打開和關閉通訊管道- Chart2.OpenData(COD.Values, 1, COD.Unknown) Chart2.CloseData(COD.Values) End Sub 你點擊第二個圖表的"獲取股票報價"按鈕的時候,代碼建立一個新的線程--同時激活計時器,這樣窗體才能夠顯示線程的狀態信息:
Private Sub btnGetStockQuote2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnGetStockQuote2.Click Dim sq As New StockQuote sq.StockSymbol = cmbStocks2.SelectedItem sq.ChartControl = Chart2 t2 = New Thread(AddressOf sq.InvokeWebService) t2.Start()
'激活暫停和停止按鈕 btnPauseContinue.Enabled = True btnStop.Enabled = True '激活計時器控件 Timer1.Enabled = True End Sub 按F5測試這兩個圖表(圖7所示)。為每個圖表選擇一只股票,你將看到這兩個圖表同步顯示。
Private Sub btnPauseContinue_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnPauseContinue.Click ' 假如線程處于睡眠和運行狀態就掛起它 If t2.ThreadState = ThreadState.WaitSleepJoin _ Or t2.ThreadState = ThreadState.Running Then t2.Suspend() btnPauseContinue.Text = "Continue" Else ' 繼續該線程 t2.Resume() btnPauseContinue.Text = "Pause" End If End Sub 停止線程則使用Abort()方法:
Private Sub btnStop_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnStop.Click Try If Not t2.ThreadState = ThreadState.Stopped Then btnPauseContinue.Enabled = False btnStop.Enabled = False t2.Abort() End If Catch ex As Exception MsgBox(ex.ToString) End Try End Sub 通過運行示例項目,你會發現自己已經能夠使用多線程技術建立應用程序,使應用程序在執行后臺事務的時候,仍然保持響應。盡管本文的示例使用的是Web服務,但是相同的原則也可以應用于其它類型的后臺事務。例如,你可以改變這個應用程序以讀取外部設備(例如溫度計或血壓計監視設備)的數據。