Visual Basic 2008 BackgroundWorker Cancel/Progress

disrupt
disrupt used Ask the Experts™
on
Hey I have the following code I'm trying to get my cancel to work on form_closing and get my progress bar (ProgressBar1) working.  I'm not sure how to use ReportProgress correctly to show the progress and not sure how to use CancellationPending correctly to correctly stop my program.
Public Class Form1

    Private WithEvents BGW As New System.ComponentModel.BackgroundWorker

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If Not BGW.IsBusy Then
            BGW.WorkerReportsProgress = True
			BGW.WorkerSupportsCancellation = True
            Button1.Enabled = False
            ListView1.Items.Clear()
			ProgressBar1.Value = 0
            BGW.RunWorkerAsync()
        End If
    End Sub

    Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
        Dim StartingPath As String = My.Computer.FileSystem.SpecialDirectories.MyDocuments
        Dim File As String = "*.csv"
        FindFiles(StartingPath, File)
    End Sub

    Private Sub FindFiles(ByVal Path As String, ByVal File As String)
        Try
            Dim di As New System.IO.DirectoryInfo(Path)
            Try
                For Each fi As System.IO.FileInfo In di.GetFiles(File)
                    BGW.ReportProgress(-1, fi)
                Next
            Catch ex As Exception
            End Try
            Try
                For Each SubDI As System.IO.DirectoryInfo In di.GetDirectories
                    FindFiles(SubDI.FullName, File)
                Next
            Catch ex As Exception
            End Try
        Catch ex As Exception
        End Try
    End Sub

    Private Sub BGW_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
        Dim fi As System.IO.FileInfo = CType(e.UserState, System.IO.FileInfo)
        Dim lvi As New ListViewItem(fi.Name)
		ProgressBar1.Value = e.ProgressPercentage
        lvi.SubItems.Add(fi.DirectoryName)
		ListView1.Items.Add(lvi)
    End Sub

    Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
        MessageBox.Show("Done Searching!")
        Button1.Enabled = True
    End Sub
	
	Private Sub ShowCSVFiles_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        BGW.CancelAsync()
    End Sub

End Class

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
High School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009
Commented:
Well...a progress bar doesn't make much sense for this process as it is a RECURSIVE algorithm.  When it starts we have NO IDEA how many items will be found/processed therefore we can't report back any meaningful progress!  I would just use a ProgressBar with the Style set to Marquee.  In that mode it just continuously animates over and over to show that it's "busy".

To cancel the worker you simply check the bgw.CancellationPending flag and exit out of the sub if appropriate:
    Private Sub FindFiles(ByVal Path As String, ByVal File As String)
        If Not BGW.CancellationPending Then
            Try
                Dim di As New System.IO.DirectoryInfo(Path)
                Try
                    For Each fi As System.IO.FileInfo In di.GetFiles(File)
                        BGW.ReportProgress(-1, fi)
                        If BGW.CancellationPending Then
                            Exit Sub
                        End If
                    Next
                Catch ex As Exception
                End Try
                Try
                    For Each SubDI As System.IO.DirectoryInfo In di.GetDirectories
                        FindFiles(SubDI.FullName, File)
                        If BGW.CancellationPending Then
                            Exit Sub
                        End If
                    Next
                Catch ex As Exception
                End Try
            Catch ex As Exception
            End Try
        End If
    End Sub

Open in new window

Author

Commented:
Hey it works fine when I have it called from a button but when I use it on form_closing I get a TargetInvocationException is that because of the events I have on Completion?
Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
        MsgBox("Scan Complete", MsgBoxStyle.Information, "")
        ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
        Button1.Enabled = True
    End Sub

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Try checking "e.Cancelled":
    Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
        If Not e.Cancelled Then
            MessageBox.Show("Scan Complete", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
            Button1.Enabled = True
        End If
    End Sub

Open in new window

Author

Commented:
I tried using that, when I close the form I still get the messagebox displaying "scan complete" so it looks like it's still executing and still get the TargetInvocationException
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009
Commented:
Ah...at the bottom of DoWork, set the e.Cancel property:
    Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
        Dim StartingPath As String = My.Computer.FileSystem.SpecialDirectories.MyDocuments
        Dim File As String = "*.csv"
        FindFiles(StartingPath, File)

        If BGW.CancellationPending Then
            e.Cancel = True
        End If
    End Sub

Open in new window

Éric MoreauSenior .Net Consultant
Top Expert 2016

Commented:

Author

Commented:
hmm I tried that it still didn't work I got it working using the following ? Is what I have ok? It does handle it fine
    Private Sub BGW_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
        If BGW.CancellationPending = False Then
            Dim fi As System.IO.FileInfo = CType(e.UserState, System.IO.FileInfo)
            Dim lvi As New ListViewItem(fi.Name)
            lvi.SubItems.Add(fi.FullName)
            ListView1.Items.Add(lvi)
            ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
        ElseIf BGW.CancellationPending = True Then
            Exit Sub
        End If
    End Sub

    Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
        If Me.Visible = True Then
            MessageBox.Show("Scan Complete", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
            Button1.Enabled = True
        ElseIf Me.Visible = False Then
            Exit Sub
        End If
    End Sub

Open in new window

Author

Commented:
Also for the progress bar I tried using ProgressBar.Style = ProgressBarStyle.Marquee at the start of the button is it suppose to animate? It seems to just stay the way it is
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Not sure where you went wrong...can you post the whole thing?

Author

Commented:
sure I just need to get the progressbar working =O
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If Not BGW.IsBusy Then
            BGW.WorkerReportsProgress = True
            BGW.WorkerSupportsCancellation = True
            Button1.Enabled = False
            ListView1.Items.Clear()
            ProgressBar1.Style = ProgressBarStyle.Marquee
            BGW.RunWorkerAsync()
        End If
    End Sub

    Private Sub BGW_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
        Dim StartingPath As String = "c:\"
        Dim File As String = "*.csv"
        FindFiles(StartingPath, File)
        If BGW.CancellationPending Then
            e.Cancel = True
        End If
    End Sub

    Private Sub FindFiles(ByVal Path As String, ByVal File As String)
        If Not BGW.CancellationPending Then
            Try
                Dim di As New System.IO.DirectoryInfo(Path)
                Try
                    For Each fi As System.IO.FileInfo In di.GetFiles(File)
                        BGW.ReportProgress(-1, fi)
                        If BGW.CancellationPending Then
                            Exit Sub
                        End If
                    Next
                Catch ex As Exception
                End Try
                Try
                    For Each SubDI As System.IO.DirectoryInfo In di.GetDirectories
                        FindFiles(SubDI.FullName, File)
                        If BGW.CancellationPending Then
                            Exit Sub
                        End If
                    Next
                Catch ex As Exception
                End Try
            Catch ex As Exception
            End Try
        End If
    End Sub

    Private Sub BGW_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BGW.ProgressChanged
        If BGW.CancellationPending = False Then
            Dim fi As System.IO.FileInfo = CType(e.UserState, System.IO.FileInfo)
            Dim lvi As New ListViewItem(fi.Name)
            lvi.SubItems.Add(fi.FullName)
            ListView1.Items.Add(lvi)
            ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
        ElseIf BGW.CancellationPending = True Then
            Exit Sub
        End If
    End Sub

    Private Sub BGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
        If Me.Visible = True Then
            MessageBox.Show("Scan Complete", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
            Button1.Enabled = True
        ElseIf Me.Visible = False Then
            Exit Sub
        End If
    End Sub

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Looks like that should work...

...make sure that the ProgressBar is VISIBLE:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If Not BGW.IsBusy Then
            BGW.WorkerReportsProgress = True
            BGW.WorkerSupportsCancellation = True
            Button1.Enabled = False
            ListView1.Items.Clear()
            ProgressBar1.Visible = True
            ProgressBar1.Style = ProgressBarStyle.Marquee
            BGW.RunWorkerAsync()
        End If
    End Sub

Then hide it again when you're all done in the RunWorkerCompleted() event.

Author

Commented:
Ya I just tried it creating a little test app and it worked fine gonna try it on my other cpu my progressbar looks different might have something to do with my theme will find out =) thanks for ur help !!!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial