如何跟踪多个 BackgroundworkerX.Runworkercompleted 操作

How to track multiple BackgroundworkerX.Runworkercompleted operations

我正在尝试使用单个处理程序来涵盖多个 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

"Do Work Here" 部分没有任何内容,因为我不知道如何捕获并且无法找到 backgroundworkercompleted 事件 ID 的详细信息。

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

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

检查this out for some examples of using BackgroundWorker objects, including passing data out using e.Result. You might also like to checkout my own 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 class.

的多个实例
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