如何使用一个BackgroundWorker执行不同的活动?

时间:2011-03-11 19:20:10

标签: .net vb.net backgroundworker

我使用VB.NET 2005编程。我使用BackgroundWorker加载大型列表或文本文件并进行处理。

是否可以使用相同的后台工作程序来处理其他内容,即处理已加载的文本文件? 像

这样的东西
Dim bwkMain as New BackgroundWorker()

如果可能的话,我该如何以与第一个相同的形式实现它呢?

修改
问题是:在完成一项任务后,是否可以将相同的BackgroundWorker用于另一项任务?

3 个答案:

答案 0 :(得分:7)

可以让单个BackgroundWorker执行两个或更多不同的操作。需要注意的是,如果您尝试让BackgroundWorker一次执行多项操作,则会导致代码失败。

以下是如何让BackgroundWorker进行多项活动的简要概述。

  1. 检查BackGroundWorker是否正在处理某些事情。
    • 如果它已经有效,您将不得不等待它完成或取消当前活动(这将要求您在DoWork事件中采用不同的编码样式。)
    • 如果它不起作用,您可以安全地继续下一步。
  2. 使用参数(或参数)调用BackgroundWorker的RunWorkerAsync方法,该参数指定要执行的操作。
  3. 在BackgroundWorker的DoWork事件处理程序中,检查传递的参数(e.Argument)并执行所需的活动。
  4. 以下是一些示例代码,可指导您完成:

    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
    

    这是随之而来的形式:
    Image of Form Layout for


    另请考虑阅读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)的for循环部分中的行bgwWorker_DoWork将变为SetTextSafely(safeValue & vbCrLf)



    如果您想了解有关代表的更多信息,请阅读以下文章(均来自MSDN)

答案 1 :(得分:2)

由于你不能并行运行你的两个任务,你可以在同一个背景工作者中按顺序执行它们

 BackgroundWorker1.RunWorkerAsync(args)


 Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
                                     ByVal e As System.ComponentModel.DoWorkEventArgs) _
                                     Handles BackgroundWorker1.DoWork

   DoTask1() ' Read files.
   DoTask2() ' Process data that was read.

End Sub


Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, _
                                                 ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                                                 Handles BackgroundWorker1.RunWorkerCompleted

  'Tasks Done

End Sub

答案 2 :(得分:1)

非常含糊。启动另一个后台工作程序并让第一个后台工作程序等待它完成是没有意义的。如果您可以同时执行某些操作,则只能从多个线程中获益。读取文件然后处理它是一个不能重叠的顺序操作。也许你可以同时进行一些处理,但这是你的问题无法解决的问题。