可以让一个 BackgroundWorker 做两件或多件不同的事情。需要注意的是,如果您尝试让 BackgroundWorker 一次做不止一件事,因为它会导致您的代码失败。
这里简要概述了如何让 BackgroundWorker 执行多项活动。
- 检查 BackGroundWorker 是否正在处理某事。
- 如果它已经在工作,您要么必须等待它完成,要么取消当前活动(这需要您在
DoWork 事件中采用不同的编码风格)。
- 如果它不起作用,您可以安全地继续下一步。
- 使用参数(或参数)调用 BackgroundWorker 的
RunWorkerAsync 方法,该参数指定要做什么。
- 在 BackgroundWorker 的
DoWork 事件处理程序中,检查传递的参数 (e.Argument) 并执行所需的活动。
这里有一些示例代码可以指导您完成:
Public Class Form1
Public WithEvents bgwWorker1 As System.ComponentModel.BackgroundWorker
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
bgwWorker1 = New System.ComponentModel.BackgroundWorker
With bgwWorker1
.WorkerReportsProgress = True 'we'll need to report progress
.WorkerSupportsCancellation = True 'allows the user to stop the activity
End With
End Sub
Private Sub Form1_Disposed() Handles Me.Disposed
'you'll need to dispose the backgroundworker when the form closes.
bgwWorker1.Dispose()
End Sub
Private Sub btnStart_Click() Handles btnStart.Click
'check if the backgroundworker is doing something
Dim waitCount = 0
'wait 5 seconds for the background worker to be free
Do While bgwWorker1.IsBusy AndAlso waitCount <= 5
bgwWorker1.CancelAsync() 'tell the backgroundworker to stop
Threading.Thread.Sleep(1000) 'wait for 1 second
waitCount += 1
Loop
'ensure the worker has stopped else the code will fail
If bgwWorker1.IsBusy Then
MsgBox("The background worker could not be cancelled.")
Else
If optStep2.Checked Then
bgwWorker1.RunWorkerAsync(2)
ElseIf optStep3.Checked Then
bgwWorker1.RunWorkerAsync(3)
End If
btnStart.Enabled = False
btnStop.Enabled = True
End If
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
'to stop the worker, send the cancel message
bgwWorker1.CancelAsync()
End Sub
Private Sub bgwWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwWorker1.DoWork
'get the value to be used in performing the steps
'in your case, you might have to convert it to a string or something
'and then do a Select Case on the result.
Dim stepValue = CInt(e.Argument)
'you cannot change the property of any control from a thread different
'from the one that created it (the UI Thread) so this code would fail.
'txtResults.Text &= "Starting count in steps of " & stepValue & vbCrLf
'to perform a thread-safe activity, use the ReportProgress method like so
bgwWorker1.ReportProgress(0, "Reported: Starting count in steps of " & stepValue & vbCrLf)
'or invoke it through an anonymous or named method
Me.Invoke(Sub() txtResults.Text &= "Invoked (anon): Starting count in steps of " & stepValue & vbCrLf)
SetTextSafely("Invoked (named): Starting count in steps of " & stepValue & vbCrLf)
For i = 0 To 1000 Step stepValue
'Visual Studio Warns: Using the iteration variable in a lambda expression may have unexpected results.
' Instead, create a local variable within the loop and assign it the value of
' the iteration variable.
Dim safeValue = i.ToString
Me.Invoke(Sub() txtResults.Text &= safeValue & vbCrLf)
'delibrately slow the thread
Threading.Thread.Sleep(300)
'check if there is a canellation pending
If bgwWorker1.CancellationPending Then
e.Cancel = True 'set this to true so we will know the activities were cancelled
Exit Sub
End If
Next
End Sub
Private Sub SetTextSafely(ByVal text As String)
If Me.InvokeRequired Then
Me.Invoke(Sub() SetTextSafely(text))
Else
txtResults.Text &= text
End If
End Sub
Private Sub bgwWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwWorker1.ProgressChanged
'everything done in this event handler is on the UI thread so it is thread safe
txtResults.Text &= e.UserState.ToString
End Sub
Private Sub bgwWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwWorker1.RunWorkerCompleted
'everything done in this event handler is on the UI thread so it is thread safe
If Not e.Cancelled Then
txtResults.Text &= "Activities have been completed."
Else
txtResults.Text &= "Activities were cancelled."
End If
btnStart.Enabled = True
btnStop.Enabled = False
End Sub
Private Sub txtResults_TextChanged() Handles txtResults.TextChanged
'place the caret at the end of the line and then scroll to it
'so that we always see what is happening.
txtResults.SelectionStart = txtResults.TextLength
txtResults.ScrollToCaret()
End Sub
End Class
这是随之而来的形式:
还可以考虑阅读 MSDN 上的以下文章:
编辑
以上代码仅适用于 VB 10 (VS 2010)。为了在其他版本的 VB 中实现相同的代码,您必须编写大量代码,因为它们不支持匿名委托。
在旧版本的 VB 中,行
Public Sub Sample()
Me.Invoke(Sub() txtResults.Text &= safeValue & vbCrLf)
End Sub
翻译成这样的:
Public Delegate AnonymousMethodDelegate(value as String)
Public Sub AnonymousMethod(value as String)
txtResults.Text &= value
End Sub
Public Sub Sample()
Me.Invoke(New AnonymousMethodDelegate(AddressOf AnonymousMethod), safeValue & vbCrLf)
End Sub
按照以下步骤使代码在 VB 10 之前的版本中工作
添加此委托
Delegate Sub SetTextSafelyDelegate(ByVal text As String)
然后把所有的Me.Invoke(Sub() SetTextSafely(text))改成
Me.Invoke(New SetTextSafelyDelegate(AddressOf SetTextSafely), text)
另请注意,在我使用匿名委托设置文本的任何地方,您都必须重写代码以调用 SetTextSafely 方法。
例如,bgwWorker_DoWork 的 for 循环部分中的行 Me.Invoke(Sub() txtResults.Text &= safeValue & vbCrLf) 将变为 SetTextSafely(safeValue & vbCrLf)
如果您想了解更多关于委托的信息,请阅读以下文章(均来自 MSDN)