locked
BackgroundWorker Strangeness RRS feed

  • Question

  • Here is a very simplified example to demonstrate the issue.  This works just perfectly:

    Dim MyBW As BackgroundWorker
    Dim bwWorkers As New List(Of BackgroundWorker)
    
    Private Sub btnDoSomething_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles btnDoSomething.Click
    
        MyBW = New BackgroundWorker
        Try
            With MyBW
                .WorkerReportsProgress = True
                .WorkerSupportsCancellation = True
            End With
            bwWorkers.Add(MyBW)
            MyBW.RunWorkerAsync()
        Catch ex As Exception
        
        End Try
    
    End Sub
    
    Private Sub MyBW_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles MyBW.DoWork
    
        Stop  'This is just for testing.
    
    End Sub
    

    But, If I have several different BackgroundWorkers, and want to reduce coding, I try this way:

    Dim bwThis As BackgroundWorker Dim bwThat As Backgroundworker Dim bwWorkers As New List(Of BackgroundWorker) Private Sub DoThis_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThis.Click Dim isOK As Boolean = start_background_worker(bwThis) End Sub Private Sub DoThat_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThat.Click Dim isOK As Boolean = start_background_worker(bwThat) End Sub Private Function start_background_worker(ByRef bw As BackgroundWorker) As Boolean Try bw = New BackgroundWorker With bw .WorkerReportsProgress = True .WorkerSupportsCancellation = True End With bwWorkers.Add(bw) bw.RunWorkerAsync() Return True Catch ex As Exception Return False End Try End Function

    Private Sub bwThis_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwThis.DoWork
    Stop 'This is just for testing.
    End Sub

    Private Sub bwThat_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwThat.DoWork
    Stop 'This is just for testing.
    End Sub

    Now I run into the problem.  When I click one or the other button to start the job, it doesn't start, and therefore doesn't hit the Stop statement in the DoWork method.  If I stop the Background worker, then start it a second time, it then works and hits the Stop statement.

    One of the 2 BackgroundWorkers usually starts fine, and the other doesn't, and must be stopped/started again to work.  In another application, even the first and only BackgroundWorker has the issue.

    Once it is restarted, everything works fine, and all of the BackgroundWorker events work properly.

    Any idea what could be causing this?  Thanks...


    Ron Mittelman

    Friday, June 7, 2013 3:39 PM

Answers

  • Since you're creating these on the fly, and doing so within a method that is ByRef, and not directly on the variable, you'll need to use AddHandler instead of "Handles" to subscribe to the appropriate DoWork event.  Try this:

    Dim bwThis As BackgroundWorker
    Dim bwThat As Backgroundworker
    Dim bwWorkers As New List(Of BackgroundWorker)
    
    Private Sub DoThis_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThis.Click
        Dim isOK As Boolean = start_background_worker(bwThis, AddressOf bwThis_DoWork)
    End Sub
    
    Private Sub DoThat_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThat.Click
        Dim isOK As Boolean = start_background_worker(bwThat, AddressOf bwThat_DoWork)
    End Sub
    
    Private Function start_background_worker(ByRef bw As BackgroundWorker, ByVal handler As DoWorkEventHandler) As Boolean
        Try
            bw = New BackgroundWorker
            With bw
                .WorkerReportsProgress = True
                .WorkerSupportsCancellation = True
            End With
    
            ' Add your event handler
            AddHandler bw, handler
    
            bwWorkers.Add(bw)
            bw.RunWorkerAsync()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    
    ' Remove the "Handles" declarations...
    Private Sub bwThis_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) 
        Stop  'This is just for testing.
    End Sub
    Private Sub bwThat_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) 
        Stop  'This is just for testing.
    End Sub


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by RMittelman Friday, June 7, 2013 9:09 PM
    Friday, June 7, 2013 4:09 PM

All replies

  • Since you're creating these on the fly, and doing so within a method that is ByRef, and not directly on the variable, you'll need to use AddHandler instead of "Handles" to subscribe to the appropriate DoWork event.  Try this:

    Dim bwThis As BackgroundWorker
    Dim bwThat As Backgroundworker
    Dim bwWorkers As New List(Of BackgroundWorker)
    
    Private Sub DoThis_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThis.Click
        Dim isOK As Boolean = start_background_worker(bwThis, AddressOf bwThis_DoWork)
    End Sub
    
    Private Sub DoThat_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles DoThat.Click
        Dim isOK As Boolean = start_background_worker(bwThat, AddressOf bwThat_DoWork)
    End Sub
    
    Private Function start_background_worker(ByRef bw As BackgroundWorker, ByVal handler As DoWorkEventHandler) As Boolean
        Try
            bw = New BackgroundWorker
            With bw
                .WorkerReportsProgress = True
                .WorkerSupportsCancellation = True
            End With
    
            ' Add your event handler
            AddHandler bw, handler
    
            bwWorkers.Add(bw)
            bw.RunWorkerAsync()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    
    ' Remove the "Handles" declarations...
    Private Sub bwThis_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) 
        Stop  'This is just for testing.
    End Sub
    Private Sub bwThat_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) 
        Stop  'This is just for testing.
    End Sub


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by RMittelman Friday, June 7, 2013 9:09 PM
    Friday, June 7, 2013 4:09 PM
  • Hi Reed,

    Thanks for the quick answer.  I'm not sure I understand, however:

    Why do you think it works as-is the second and subsequent times I use a given BackgroundWorker, but not the first time?

    I thought ByRef meant that I WAS working directly on the variable.  Are you saying that if I remove ByRef, it would work as-is, or would still need the AddressOf handler?

    Thanks...


    Ron Mittelman

    Friday, June 7, 2013 4:45 PM

  • I thought ByRef meant that I WAS working directly on the variable.  Are you saying that if I remove ByRef, it would work as-is, or would still need the AddressOf handler?

    Thanks...


    Ron Mittelman

    You are - and, in theory, what you are doing should work fine.  I believe the problem is actually in the "Handles" clause - when you use Handles, the VB compiler is hooking up the subscription for you (doing the AddHandler line).  However, since you're creating the BW instance within a method, and, at the point where you instantiate the BW the variable has a different "name" (since it's ByRef in the method), it's not "seeing" that it's the same variable, and it's not subscribing properly.

    My solution eliminates that as an issue, since it just does the subscription itself.  It's basically what you'd write in most other .NET languages (the "Handles" option is fairly unique to VB).


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Friday, June 7, 2013 5:59 PM
  • Hi Reed,

    I tried your solution and it did not work for me.  Not sure why.  Even specifying the handler and explicitly adding it, the DoWork event is not entered the first time.

    I will mark your answer as THE answer anyway, because it makes sense.  It's not worth the time to debug this, given I only save 6 or 7 lines of code (including the VB-centric With and End With).  Unless there are many BackgroundWorkers being used, the benefit of calling a function to do this is minimal.

    Thanks anyway...


    Ron Mittelman

    Friday, June 7, 2013 9:09 PM