none
Background worker problems! RRS feed

  • Question

  • I found like 100 tutorials for this background worker, but none for my needs!

    I want to cancel the thread using CancelAsync() , but all the tutorials do it only in a loop, like this:

    Private Sub BW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BW.DoWork
      For i As Integer = 0 To 30000
        If BW.CancellationPending Then
          e.Cancel = True
          Exit Sub
        End If
      Next
    End Sub


    But what if I don't have a loop in the sub, like so:

    Private Sub BW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BW.DoWork
    If BW.CancellationPending Then
          e.Cancel = True
          Exit Sub
        End If
         text1.Text = "bla"
         text2.Text = "bla2"
         'any code without loop!
         'other code here...
         'other code here...
         'other code here...
    End Sub
    

    How can this be canceled?
    And how to implement a progress bar for it?
    Proud tutorial creator for hackyourwindows.com :)
    Monday, November 30, 2009 11:02 AM

Answers

  • You cant stop backgroundworker abruptly. After certain step of your lengthy job, you need to poll the value of cancellationpending and if its true then need to stop there. And this is very useful when you want to control where is a good place to stop. For progressbar you need to use reportprgress. Check following example, control needed
    A BackGroundWorker named  BackGroundWorker1
    A Label named  lblCancel
    A Button Called btnCancel
    A button Called  btnStart
    A progressbar called ProgressBar1

    Public Class Form1
    
        Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
            If Not BackgroundWorker1.IsBusy Then
                BackgroundWorker1.RunWorkerAsync()
            End If
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    
            Dim i As Integer = 1
            'Do first set of work
            System.Threading.Thread.Sleep(200)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(25) ' 25% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do second set of work
            i += 1
    
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(50) ' 50% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do third set of work
            i += 1
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(75) ' 75% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do Fourth set of work
            i += 1
            Debug.WriteLine(i)
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(100) ' 100% finished
            Debug.WriteLine(i)
    
            
    
        End Sub
     
    
        Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
            If BackgroundWorker1.IsBusy Then
                BackgroundWorker1.CancelAsync()
                lblCancel.Text = "Cancellation Pending."
            End If
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.WorkerSupportsCancellation = True
            BackgroundWorker1.WorkerReportsProgress = True
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            If Not BackgroundWorker1.CancellationPending Then
                ProgressBar1.Value = e.ProgressPercentage
            End If
    
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            If Not e.Cancelled Then
                lblCancel.Text = "Operation Completed Succefully."
            Else
                lblCancel.Text = "Operation Cancelled"
            End If
        End Sub
    End Class

    For pause and resume please check following
    http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/50bb9b66-831e-4522-8a73-b990782d44ff
    Arjun Paudel
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 1:17 PM
  • You can do as follow

     Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            If TextBox1.InvokeRequired Then
                Dim d As New DelUpdateText(AddressOf UpdateText)
                TextBox1.Invoke(d, "Your Text Here")
            Else
                UpdateText("Your Text Here")
            End If
    
        End Sub
       
        Private Delegate Sub DelUpdateText(ByVal TextToUpdate As String)
        Private Sub UpdateText(ByVal TextToUpdate As String)
            TextBox1.Text = TextToUpdate
        End Sub
    Or with function, dirty method, but sub can be used in 2010

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            If TextBox1.InvokeRequired Then
                TextBox1.Invoke(Function() UpdateText("Your Text Here"))
            Else
                UpdateText("Your Text Here")
            End If
        End Sub
          Private Function UpdateText(ByVal TextToUpdate As String) As Integer
            TextBox1.Text = TextToUpdate
        End Function



    Arjun Paudel
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 2:51 PM
  • You can use Thread insert Backgroundworker.
        Sub Main()
            Dim Ea As New Threading.Thread(AddressOf ET) _
            With {.IsBackground = True}
            Ea.Start()
            Do
                If Console.ReadLine() = "a" Then
                    Ea.Abort()
                End If
            Loop
        End Sub
    
        Dim No% = 0
        Sub ET()
            Do
                No += 1
                Console.WriteLine(No)
                Threading.Thread.Sleep(3000)
            Loop
        End Sub
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 3:32 PM

All replies

  • I see two pieces of obvious wrong code, what is it you want to achieve?


    Success
    Cor
    Monday, November 30, 2009 11:26 AM
  • I want to stop the backgroundworker by pressing a button. Have in mind that the code i use in the DoWork of the backgroundworker needs to run just once. No Loop, nothing.
    Proud tutorial creator for hackyourwindows.com :)
    Monday, November 30, 2009 11:34 AM
  • You cant stop backgroundworker abruptly. After certain step of your lengthy job, you need to poll the value of cancellationpending and if its true then need to stop there. And this is very useful when you want to control where is a good place to stop. For progressbar you need to use reportprgress. Check following example, control needed
    A BackGroundWorker named  BackGroundWorker1
    A Label named  lblCancel
    A Button Called btnCancel
    A button Called  btnStart
    A progressbar called ProgressBar1

    Public Class Form1
    
        Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
            If Not BackgroundWorker1.IsBusy Then
                BackgroundWorker1.RunWorkerAsync()
            End If
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    
            Dim i As Integer = 1
            'Do first set of work
            System.Threading.Thread.Sleep(200)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(25) ' 25% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do second set of work
            i += 1
    
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(50) ' 50% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do third set of work
            i += 1
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(75) ' 75% finished
            If BackgroundWorker1.CancellationPending Then e.Cancel = True : Exit Sub
            Debug.WriteLine(i)
            'Do Fourth set of work
            i += 1
            Debug.WriteLine(i)
            System.Threading.Thread.Sleep(3000)  ' just for demonstration to represent some work
            BackgroundWorker1.ReportProgress(100) ' 100% finished
            Debug.WriteLine(i)
    
            
    
        End Sub
     
    
        Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
            If BackgroundWorker1.IsBusy Then
                BackgroundWorker1.CancelAsync()
                lblCancel.Text = "Cancellation Pending."
            End If
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.WorkerSupportsCancellation = True
            BackgroundWorker1.WorkerReportsProgress = True
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            If Not BackgroundWorker1.CancellationPending Then
                ProgressBar1.Value = e.ProgressPercentage
            End If
    
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            If Not e.Cancelled Then
                lblCancel.Text = "Operation Completed Succefully."
            Else
                lblCancel.Text = "Operation Cancelled"
            End If
        End Sub
    End Class

    For pause and resume please check following
    http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/50bb9b66-831e-4522-8a73-b990782d44ff
    Arjun Paudel
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 1:17 PM
  • Ok, but what if i have a set of work that lasts about 2 min, and 30 sets of work? That would mean i have to use 30 ifs! It that good?
    Let me detail:

    Private Sub BGW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
    
           Call web1()
           Call web2()
           Call web3()
    
        End Sub
    
    Private Sub web1()
           Webbrowser1.Navigate("site")
           call wait() ' waiting for document to complete
           webbrowser1.document,get....
           webbrowser1.navigate...
        End sub
    
    Private Sub web2()
           Webbrowser1.Navigate("site2")
           call wait() ' waiting for document to complete
           webbrowser1.document,get2....
           webbrowser1.navigate...
        End sub
    
    So i should put an If before every call...
    Ok... then how can I update a text box with some info from this thread? Like if I have a txtresults.Text to update on the main form? ( I understand it something involving delegates, but I didn't quite understand what it means...). Detailed:
    Private Sub BGW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
    
           Call web1()
           results.Text = "web1 complete!" 'update main thread's result.Text here...
           Call web2()
           Call web3()
    
        End Sub
    
     Edit - I think it can be done with progress change... let's me study that...
    Monday, November 30, 2009 2:32 PM
  • You can do as follow

     Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            If TextBox1.InvokeRequired Then
                Dim d As New DelUpdateText(AddressOf UpdateText)
                TextBox1.Invoke(d, "Your Text Here")
            Else
                UpdateText("Your Text Here")
            End If
    
        End Sub
       
        Private Delegate Sub DelUpdateText(ByVal TextToUpdate As String)
        Private Sub UpdateText(ByVal TextToUpdate As String)
            TextBox1.Text = TextToUpdate
        End Sub
    Or with function, dirty method, but sub can be used in 2010

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            If TextBox1.InvokeRequired Then
                TextBox1.Invoke(Function() UpdateText("Your Text Here"))
            Else
                UpdateText("Your Text Here")
            End If
        End Sub
          Private Function UpdateText(ByVal TextToUpdate As String) As Integer
            TextBox1.Text = TextToUpdate
        End Function



    Arjun Paudel
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 2:51 PM
  • You can use Thread insert Backgroundworker.
        Sub Main()
            Dim Ea As New Threading.Thread(AddressOf ET) _
            With {.IsBackground = True}
            Ea.Start()
            Do
                If Console.ReadLine() = "a" Then
                    Ea.Abort()
                End If
            Loop
        End Sub
    
        Dim No% = 0
        Sub ET()
            Do
                No += 1
                Console.WriteLine(No)
                Threading.Thread.Sleep(3000)
            Loop
        End Sub
    • Marked as answer by Jeff Shan Monday, December 7, 2009 1:40 AM
    Monday, November 30, 2009 3:32 PM