Searching the File Set
Finally, the code makes recursive calls to a method called SearchDirectoryRecursive
to find the files that match and display the same.
' Process all the files in the current directory
' and get the count of files completed...
filesdone = filesdone + _
'report progress as of now...
filesdone / totalfiles) * 100))
For Each file As FileInfo In directoryInfo.GetFiles()
If file.Name.ToLower.IndexOf( _
search.ToLower) > 0 Then
If Not worker.CancellationPending Then
e.Cancel = True
This method performs three important tasks. The first two lines retrieve the number of files to be searched in the current directory and call the interface to set the completed search percentage via the ReportProgress
method. Note that it does this before actually processing the files, because doing such processing inside a For
loop becomes complex. It's important not to over-inflate the importance of the progress complete feature, because it just adds overhead to the intended search functionality.
The code iterates through the files, comparing each file name against the search term that the user entered. When Indexof
returns a value greater than zero the file is a match, and you need to display it in the search results. In each iteration, the loop checks to see if the client has cancelled the search task by checking the BackgroundWorker.CancellationPending
property. If the property value is True, the client has requested cancellation of background task, so you need to set the eventArgs.Cancel
property to True, which will cancel the task. If the user hasn't cancelled, then the code continues to the third important task: invoking the delegate using callback.Invoke
(file), which passes the current file name to the method that displays search results in the ListView.
event can complete in any of three ways:
- The DoWork event code exits normally
- An unhandled exception occurs
- The user requests cancellation
No matter which way it completes, the event raises the RunWorkerCompleted
event, where you can respond appropriately. For example, you can use the RunWorkerEventArgs.Cancelled
property to check the user cancelled the operation, and if so return message confirming that the search was stopped. For errors, check the RunWorkerCancelEventArgs.Error
property, which provides the exception details. The DoWork
event also gives you access to the RunWorkerEventArgs.Result
property, which can be any object that you need to return to the client.
Private Sub searchFolders_RunWorkerCompleted( _
ByVal sender As Object, _
ByVal e As System.ComponentModel. _
Dim obj As System.ComponentModel. _
BackgroundWorker = CType(sender, _
If Not e.Error Is Nothing Then
ElseIf e.Cancelled Then
callComplete("Stopped the search.")
The last important event is ProgressChanged
. The method accepts a ProgressChangedEventArgs argument.
Private Sub searchFolders_ProgressChanged( _
ByVal sender As Object, ByVal e As _
progressChange = e.ProgressPercentage
property returns the percentage completed value (set in the DoWork
event by calling the ReportProgress
method). You can get access to the state via the ProgressChangedEventArgs.UserState
property, which is an overloaded parameter of ReportProgress
. This event fires each time the progress changes; therefore you should use a private variable to hold the current status. You inform the caller on the progress completion via a public Progress
So far, you've created a rich component that uses BackgroundWorker to search local fixed drives for matching file names using the BackGroundWorker class. The component can report search progress and lets users cancel the search task. It invokes delegate callbacks to registered methods passing information about matching files as FileInfo instances. Finally, it handles error messages.
Now take a look at the UI implementation.
The initial form load event creates an instance of the ContentSearcher.
Private objContentsearcher As ContentSearcher
objContentsearcher = New ContentSearcher( _
AddressOf FileInformation, AddressOf ProcessComplete)
The first delegate references a method to display matching files, and the second report on the final search statuswhether the user cancelled, an error occurred, or the process completed successfully.
You invoke the search by calling the ContentSearcher.SearchContent
Private Sub SearchContent(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
If Not isWorkerStarted Then
Dim a As Integer = System.Threading.Thread. _
Dim getWorker As _
System.ComponentModel.BackgroundWorker = _
lblProgress.Text = _
"Scanning started...please wait"
pgBar.Value = 0
pgBar.Visible = True
isWorkerStarted = True
The Boolean variable isWorkerStarted
ensures that users can't perform more than one search at a time. Although you must write it each time, you should consider this technique as a standard feature; you need to implement this or a similar mechanism on the UI side whenever users or events launch asynchronous calls. The method initializes some control values and calls the ContentSearcher.RunWorkerAsync
method, passing the search text as a parameter, for this simple example. Note that you could just as easily pass any other type of object, for example, an XML document that contained user preferences and additional search restrictions (e.g. search all files between 10/7/2004 and 10/8/2004) When called, the BackGroundWorker executes the DoWork
event on a worker thread and the UI remains responsive, so you can display messages and search progress.