如何跟踪多个BackgroundworkerX.Runworker完成的操作

时间:2018-11-12 01:05:01

标签: vb.net backgroundworker background-process

我正在尝试使用单个处理程序来覆盖多个backgroundworker活动的结束,并且找不到使用backgroundworkercompleted事件获取有关特定backgroundworker信息的方法。 我捕获事件的代码如下:

Private Sub BGx_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted, BackgroundWorker2.RunWorkerCompleted, BackgroundWorker3.RunWorkerCompleted, BackgroundWorker4.RunWorkerCompleted, BackgroundWorker5.RunWorkerCompleted, BackgroundWorker6.RunWorkerCompleted, BackgroundWorker7.RunWorkerCompleted, BackgroundWorker8.RunWorkerCompleted

    'Do work here based on completed Backgroundworker

    For BG = 1 To 8
        If Not DSWorkers(BG).IsBusy Then
            If DStatus(BG) = -2 Then : DStatus(BG) = -1 : End If
        End If
    Next

    Complete()
End Sub

“在这里工作”部分没有任何内容,因为我不知道如何捕获并且无法找到backgroundworkercompleted事件ID的详细信息。

请-有关如何识别特定的已完成BackgroundWorker的任何提示

1 个答案:

答案 0 :(得分:1)

与所有事件处理程序一样,sender参数是对引发事件的对象的引用,因此您可以访问通过该事件完成工作的实际BackgroundWorker。如果您还需要其他数据,则将其分配给e.Result事件处理程序中的DoWork属性,然后从e.Result事件处理程序中的RunWorkerCompleted属性中获取。 e.Result用于从DoWork事件处理程序中获取数据,就像e.Argument用于获取数据。

签出this以获得使用BackgroundWorker对象的一些示例,包括使用e.Result传递数据。您可能还想检出自己的BackgroundMultiWorker class,该方法基本上将多个BackgroundWorker对象的功能组合到单个BackgroundMultiWorker对象中。它使用令牌标识每个任务。

编辑:

下面是一个可以帮助解决此问题和总体任务的示例:

Imports System.ComponentModel
Imports System.Threading

Public Class Form1

    Private ReadOnly resultsByWorker As New Dictionary(Of BackgroundWorker, BackgroundWorkerResult)
    Private ReadOnly rng As New Random

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'The NumericUpDown is used to select the index of a BackgroundWorker to cancel.
        With NumericUpDown1
            .DecimalPlaces = 0
            .Minimum = 0
            .Maximum = 9
        End With
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'Create 10 BackgroundWorkers and run them.
        For i = 1 To 10
            Dim worker As New BackgroundWorker

            resultsByWorker.Add(worker, New BackgroundWorkerResult)

            AddHandler worker.DoWork, AddressOf workers_DoWork
            AddHandler worker.RunWorkerCompleted, AddressOf workers_RunWorkerCompleted

            worker.WorkerSupportsCancellation = True

            worker.RunWorkerAsync()
        Next
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim index = Convert.ToInt32(NumericUpDown1.Value)
        Dim worker = resultsByWorker.Keys.ToArray()(index)

        If worker.IsBusy Then
            'Cancel the BackgroundWorker at the specified index.
            worker.CancelAsync()
        End If
    End Sub

    Private Sub workers_DoWork(sender As Object, e As DoWorkEventArgs)
        Dim worker = DirectCast(sender, BackgroundWorker)

        'Do work for a random number of seconds between 10 and 20.
        Dim period = rng.Next(10, 20 + 1)

        For i = 0 To period
            If worker.CancellationPending Then
                e.Cancel = True
                Return
            End If

            'Simulate work.
            Thread.Sleep(1000)
        Next

        'The work was completed without being cancelled.
        e.Result = period
    End Sub

    Private Sub workers_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
        Dim worker = DirectCast(sender, BackgroundWorker)
        Dim result = resultsByWorker(worker)

        If e.Cancelled Then
            result.WasCancelled = True
        Else
            result.Result = CInt(e.Result)
        End If

        Dim workers = resultsByWorker.Keys.ToArray()

        If Not workers.Any(Function(bgw) bgw.IsBusy) Then
            'All work has completed so display the results.

            Dim results As New List(Of String)

            For i = 0 To workers.GetUpperBound(0)
                worker = workers(i)
                result = resultsByWorker(worker)

                results.Add($"Worker {i} {If(result.WasCancelled, "was cancelled", $"completed {result.Result} iterations")}.")
            Next

            MessageBox.Show(String.Join(Environment.NewLine, results))
        End If
    End Sub
End Class

Public Class BackgroundWorkerResult
    Public Property WasCancelled As Boolean
    Public Property Result As Integer
End Class

这里是经过改编的示例,其使用链接到BackgroundMultiWorker类的单个实例,而不是BackgroundWorker类的多个实例。

Imports System.Threading

Public Class Form1

    Private WithEvents worker As New BackgroundMultiWorker With {.WorkerSupportsCancellation = True}
    Private ReadOnly results(9) As BackgroundWorkerResult
    Private ReadOnly rng As New Random

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'The NumericUpDown is used to select the index of a BackgroundWorker to cancel.
        With NumericUpDown1
            .DecimalPlaces = 0
            .Minimum = 0
            .Maximum = results.GetUpperBound(0)
        End With
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'Create 10 BackgroundWorkers and run them.
        For i = 0 To results.GetUpperBound(0)
            results(i) = New BackgroundWorkerResult

            worker.RunWorkerAsync(i)
        Next
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim index = Convert.ToInt32(NumericUpDown1.Value)

        If worker.IsBusy(index) Then
            'Cancel the BackgroundWorker at the specified index.
            worker.CancelAsync(index)
        End If
    End Sub

    Private Sub worker_DoWork(sender As Object, e As DoWorkEventArgs) Handles worker.DoWork
        'Do work for a random number of seconds between 10 and 20.
        Dim period = rng.Next(10, 20 + 1)

        For i = 0 To period
            If worker.IsCancellationPending(e.Token) Then
                e.Cancel = True
                Return
            End If

            'Simulate work.
            Thread.Sleep(1000)
        Next

        'The work was completed without being cancelled.
        e.Result = period
    End Sub

    Private Sub workers_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        Dim result = results(CInt(e.Token))

        If e.Cancelled Then
            result.WasCancelled = True
        Else
            result.Result = CInt(e.Result)
        End If

        If Not worker.IsBusy() Then
            'All work has completed so display the results.

            Dim output As New List(Of String)

            For i = 0 To results.GetUpperBound(0)
                result = results(i)

                output.Add($"Task {i} {If(result.WasCancelled, "was cancelled", $"completed {result.Result} iterations")}.")
            Next

            MessageBox.Show(String.Join(Environment.NewLine, output))
        End If
    End Sub
End Class

Public Class BackgroundWorkerResult
    Public Property WasCancelled As Boolean
    Public Property Result As Integer
End Class