Возможно, чтобы один BackgroundWorker делал две или более разные вещи.Предостережение заключается в том, что если вы попытаетесь заставить BackgroundWorker выполнять несколько действий одновременно, так как это приведет к сбою вашего кода.
Вот краткий обзор того, как заставить BackgroundWorker выполнять несколько действий.
- Проверьте, не работает ли BackGroundWorker на чем-либо.
- Если он уже работает, вам нужно будет либо дождаться его завершения, либо отменить текущее действие (что потребует применения другого стиля кодирования в событии
DoWork
). - Если он не работает, вы можете перейти к следующему шагу.
- Вызвать метод BackgroundWorker's
RunWorkerAsync
с аргументом (или параметром), который указывает, что нужноделать. - В обработчике событий
DoWork
BackgroundWorker's проверьте переданный аргумент (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
.
Например, строка Me.Invoke(Sub() txtResults.Text &= safeValue & vbCrLf)
в разделе цикла цикла forbgwWorker_DoWork
станет SetTextSafely(safeValue & vbCrLf)
Если вы хотите узнать больше о делегатах, прочитайте следующие статьи (все из MSDN)