vb.netvisual-studio-2013backgroundworkerpostmortem-debugging

VB.Net Backgroudworker


I use Visual Studio 2013 for Visual Basic and I'm struggling to debug my multi-threaded program.

I am using a BackgroundWorker, which appears to work differently to how I think it should.

I don't understand why my program halts after processing only the first entry in my ArrayList called arFileName.

The For Each statement in BackgroundWorker1.DoWork procedure fails to iterate through the entire arFileName in the following code:

Private Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnSelectCsv.Click

    'arFileName is ArrayList and it has enormous counts
    ProgressBar1.Maximum = arFileName.Count

    Me.Cursor = Cursors.WaitCursor

    'Do background
    BackgroundWorker1.RunWorkerAsync()

    Me.Cursor = Cursors.Arrow

    MessageBox.Show("Finished!", "info", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)


End Sub


Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) _
    Handles BackgroundWorker1.DoWork

    Dim arNotFoundFile As New ArrayList

    'Confirm file exists
    For Each filename As String In arFileName ' Here!
        If Not IO.File.Exists(filename) Then

            arNotFoundFile.Add(filename)
            ProgressBar1.Value = ProgressBar1.Value + 1
        End If
    Next

End Sub

Solution

  • The backgroundworker must be set to report its progresses

     BackgroundWorker1.WorkerReportsProgress = True
    

    Then, a typical implementation could be as follows:

    Dim progress As Integer = 0
    
    Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        While (progress < 100)
            ' YOUR CODE HERE
            progress += 1
            BackgroundWorker1.ReportProgress(progress)
        End While
    End Sub
    
    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ' YOUR PROGRESSBAR VALUE HERE, USING progress VARIABLE
    End Sub
    
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        MessageBox.Show("Work completed")
    End Sub
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        BackgroundWorker1.WorkerReportsProgress = True
        BackgroundWorker1.RunWorkerAsync()
    End Sub
    

    As you can see, i've defined a progress variable, which will keep track of the percentage of work done. After we start the backgroundworker (which i do into the Form_Load event) with RunWorkerAsync, we could keep track of its progresses by the ProgressChanged event: here, we use the progress variable, modified by our work (DoWork). You could use it to set the progressbar value property. Finally, when all its done, we emit the message into the proper event, i.e. RunWorkerCompleted