Although in our simple example, it is obvious when the task has been completed you may well have scenarios where this isn't so. For example you may prefer in some cases to minimize the progress form and only have it appear back at its default size once the task is complete.
The place for the code to do this kind of task is in the RunWorkerCompleted event. Unlike the ProgressChanged event, the BGW will fire its RunWorkerCompleted event once it effectively runs out of task - in our example, therefore, once it has enumerated through every folder and file in its task.
With the ListBox, one thing you could do would be to reset the selected file back up to the first one in the list. (Again in the demo solution I have made changes to a progress label - making it totally clear to the user that the task has finished).
Private Sub bWkrFileCheck_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bWkrFileCheck.RunWorkerCompleted
If fp.ListBox1.Items.Count > 0 Then fp.ListBox1.SelectedIndex = 0
End Sub
Note the If Then statement which ensures that the app won't crash if the search had resulted in no files being found (and therefore no first item in the ListBox to select).
Task Cancellation
There is of course another situation which may cause the task to end and that is where the user decides they want to cancel it.
When you are testing this kind of project in the Visual Studio IDE you can end it by closing down the startup form or hitting the Stop Debugging button. However it might not be so good to force your users to close down the whole application if they only want to halt the background task! Happily there is another property which makes this very easy - the ReadOnly CancellationPending property - and a cancellation method of the BackgroundWorker - CancelAsync. In combination, these will enable you to offer users a get-out clause.
Add a second button to your project and name it btnStop. Insert a call to the CancelAsync method of the BGW:
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
bWkrFileCheck.CancelAsync()
End Sub
All that remains now is some way of actually terminating the running background process. In our example, exiting the FileFinder sub will do nicely:
Sub FileFinder(ByVal dir As String)
Try
If bWkrFileCheck.CancellationPending Then Exit Sub
' Display all files in a directory that match file type
For Each fname As String In Directory.GetFiles(dir)
If fname.EndsWith("txt") Then
' pass back progress message
bWkrFileCheck.ReportProgress(0, fname)
End If
Next
' A recursive call for all the subdirectories in this directory.
For Each subdir As String In Directory.GetDirectories(dir)
FileFinder(subdir)
Next
Catch ex As Exception
MessageBox.Show(ex.Message.ToString)
End Try
End Sub
Try running the project and hit the Stop button at some point in the run. This will gracefully terminate the task the very next time the FileFinder procedure runs the If CancellationPending check.