How to track multiple BackgroundworkerX.Runworkercompleted operations











up vote
0
down vote

favorite












I am trying to use a single handler to cover the end of multiple backgroundworker activities and cannot find a way to get the information about the specific backgroundworker using the backgroundworkercompleted event.
My code to catch the event is as below:



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


There is nothing on the "Do Work Here" section because I do not know how to capture and have been unable to find details of the backgroundworkercompleted event id.



Please - any pointers as to how I can identify the specific completed BackgroundWorker










share|improve this question




























    up vote
    0
    down vote

    favorite












    I am trying to use a single handler to cover the end of multiple backgroundworker activities and cannot find a way to get the information about the specific backgroundworker using the backgroundworkercompleted event.
    My code to catch the event is as below:



    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


    There is nothing on the "Do Work Here" section because I do not know how to capture and have been unable to find details of the backgroundworkercompleted event id.



    Please - any pointers as to how I can identify the specific completed BackgroundWorker










    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I am trying to use a single handler to cover the end of multiple backgroundworker activities and cannot find a way to get the information about the specific backgroundworker using the backgroundworkercompleted event.
      My code to catch the event is as below:



      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


      There is nothing on the "Do Work Here" section because I do not know how to capture and have been unable to find details of the backgroundworkercompleted event id.



      Please - any pointers as to how I can identify the specific completed BackgroundWorker










      share|improve this question















      I am trying to use a single handler to cover the end of multiple backgroundworker activities and cannot find a way to get the information about the specific backgroundworker using the backgroundworkercompleted event.
      My code to catch the event is as below:



      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


      There is nothing on the "Do Work Here" section because I do not know how to capture and have been unable to find details of the backgroundworkercompleted event id.



      Please - any pointers as to how I can identify the specific completed BackgroundWorker







      vb.net backgroundworker background-process






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 at 4:48

























      asked Nov 12 at 1:05









      Terval

      134




      134
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          As with all event handlers, the sender parameter is a reference to the object that raised the event, so you can access the actual BackgroundWorker that has completed its work via that. If you need some data other than that, you assign it to the e.Result property in the DoWork event handler and get it back from the e.Result property in the RunWorkerCompleted event handler. e.Result works for getting data out of the DoWork event handler much as e.Argument works for getting data in.



          Check 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, which basically combines the functionality of multiple BackgroundWorker objects into a single BackgroundMultiWorker object. It identifies each task using a token.



          EDIT:



          Here's an example that may help with this issue and your task in general:



          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


          Here is that example reworked to use a single instance of the BackgroundMultiWorker is linked to instead of multiple instances of the 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





          share|improve this answer























          • Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
            – Terval
            Nov 12 at 4:45












          • I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
            – Terval
            Nov 12 at 4:53












          • Looking at your Multiworker. Sounds hopeful.
            – Terval
            Nov 12 at 5:15










          • See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
            – jmcilhinney
            Nov 12 at 5:42










          • I have added the BackgroundMultiWorker example.
            – jmcilhinney
            Nov 12 at 6:09











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254809%2fhow-to-track-multiple-backgroundworkerx-runworkercompleted-operations%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          As with all event handlers, the sender parameter is a reference to the object that raised the event, so you can access the actual BackgroundWorker that has completed its work via that. If you need some data other than that, you assign it to the e.Result property in the DoWork event handler and get it back from the e.Result property in the RunWorkerCompleted event handler. e.Result works for getting data out of the DoWork event handler much as e.Argument works for getting data in.



          Check 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, which basically combines the functionality of multiple BackgroundWorker objects into a single BackgroundMultiWorker object. It identifies each task using a token.



          EDIT:



          Here's an example that may help with this issue and your task in general:



          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


          Here is that example reworked to use a single instance of the BackgroundMultiWorker is linked to instead of multiple instances of the 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





          share|improve this answer























          • Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
            – Terval
            Nov 12 at 4:45












          • I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
            – Terval
            Nov 12 at 4:53












          • Looking at your Multiworker. Sounds hopeful.
            – Terval
            Nov 12 at 5:15










          • See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
            – jmcilhinney
            Nov 12 at 5:42










          • I have added the BackgroundMultiWorker example.
            – jmcilhinney
            Nov 12 at 6:09















          up vote
          0
          down vote













          As with all event handlers, the sender parameter is a reference to the object that raised the event, so you can access the actual BackgroundWorker that has completed its work via that. If you need some data other than that, you assign it to the e.Result property in the DoWork event handler and get it back from the e.Result property in the RunWorkerCompleted event handler. e.Result works for getting data out of the DoWork event handler much as e.Argument works for getting data in.



          Check 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, which basically combines the functionality of multiple BackgroundWorker objects into a single BackgroundMultiWorker object. It identifies each task using a token.



          EDIT:



          Here's an example that may help with this issue and your task in general:



          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


          Here is that example reworked to use a single instance of the BackgroundMultiWorker is linked to instead of multiple instances of the 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





          share|improve this answer























          • Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
            – Terval
            Nov 12 at 4:45












          • I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
            – Terval
            Nov 12 at 4:53












          • Looking at your Multiworker. Sounds hopeful.
            – Terval
            Nov 12 at 5:15










          • See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
            – jmcilhinney
            Nov 12 at 5:42










          • I have added the BackgroundMultiWorker example.
            – jmcilhinney
            Nov 12 at 6:09













          up vote
          0
          down vote










          up vote
          0
          down vote









          As with all event handlers, the sender parameter is a reference to the object that raised the event, so you can access the actual BackgroundWorker that has completed its work via that. If you need some data other than that, you assign it to the e.Result property in the DoWork event handler and get it back from the e.Result property in the RunWorkerCompleted event handler. e.Result works for getting data out of the DoWork event handler much as e.Argument works for getting data in.



          Check 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, which basically combines the functionality of multiple BackgroundWorker objects into a single BackgroundMultiWorker object. It identifies each task using a token.



          EDIT:



          Here's an example that may help with this issue and your task in general:



          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


          Here is that example reworked to use a single instance of the BackgroundMultiWorker is linked to instead of multiple instances of the 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





          share|improve this answer














          As with all event handlers, the sender parameter is a reference to the object that raised the event, so you can access the actual BackgroundWorker that has completed its work via that. If you need some data other than that, you assign it to the e.Result property in the DoWork event handler and get it back from the e.Result property in the RunWorkerCompleted event handler. e.Result works for getting data out of the DoWork event handler much as e.Argument works for getting data in.



          Check 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, which basically combines the functionality of multiple BackgroundWorker objects into a single BackgroundMultiWorker object. It identifies each task using a token.



          EDIT:



          Here's an example that may help with this issue and your task in general:



          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


          Here is that example reworked to use a single instance of the BackgroundMultiWorker is linked to instead of multiple instances of the 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






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 12 at 6:08

























          answered Nov 12 at 1:34









          jmcilhinney

          25k21932




          25k21932












          • Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
            – Terval
            Nov 12 at 4:45












          • I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
            – Terval
            Nov 12 at 4:53












          • Looking at your Multiworker. Sounds hopeful.
            – Terval
            Nov 12 at 5:15










          • See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
            – jmcilhinney
            Nov 12 at 5:42










          • I have added the BackgroundMultiWorker example.
            – jmcilhinney
            Nov 12 at 6:09


















          • Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
            – Terval
            Nov 12 at 4:45












          • I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
            – Terval
            Nov 12 at 4:53












          • Looking at your Multiworker. Sounds hopeful.
            – Terval
            Nov 12 at 5:15










          • See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
            – jmcilhinney
            Nov 12 at 5:42










          • I have added the BackgroundMultiWorker example.
            – jmcilhinney
            Nov 12 at 6:09
















          Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
          – Terval
          Nov 12 at 4:45






          Thanks for that - had been trying to use the e.result method but this fails if the backgroundworker was cancelled by the user. This s really the problem since I need to do work for the specific backgroundworker IF it was cancelled by the user. I have added some code to pick up an external tag and check ALL background tasks but it would be easier if there was some id info I could get from the sender parameter .. there might be something but I have not been able to find ot.
          – Terval
          Nov 12 at 4:45














          I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
          – Terval
          Nov 12 at 4:53






          I reread your comments and I am sure the answer is in the sender parameters but how do I call them?... I will need a pointer on this since I have not found the info through my searches or by reading the syntax docs.
          – Terval
          Nov 12 at 4:53














          Looking at your Multiworker. Sounds hopeful.
          – Terval
          Nov 12 at 5:15




          Looking at your Multiworker. Sounds hopeful.
          – Terval
          Nov 12 at 5:15












          See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
          – jmcilhinney
          Nov 12 at 5:42




          See my edit for a complete code example. I'll rejig that to use a BackgroundMultiWorker too.
          – jmcilhinney
          Nov 12 at 5:42












          I have added the BackgroundMultiWorker example.
          – jmcilhinney
          Nov 12 at 6:09




          I have added the BackgroundMultiWorker example.
          – jmcilhinney
          Nov 12 at 6:09


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254809%2fhow-to-track-multiple-backgroundworkerx-runworkercompleted-operations%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Guess what letter conforming each word

          Port of Spain

          Run scheduled task as local user group (not BUILTIN)