0

So I've searched this and other sites and I have found some hints that I think should solve my problem, but for the life of me I can't get it to work. Here's an overview. I'm working on a VB.net program that finds and lists the timestamps of files as well as their exif info if they are JPG files and populates a file list. Things work fine unless a directory has many JPG files so I decided to put the code that reads the files info into a backgound worker. My file list populate routine (lstFileList_Populate) calls the BackgroundWorker1.RunWorkerAsync. When the program starts the lstFileList_Populate gets called and when I change directory it gets called again. When it gets called the second time the BackgroundWorker1 is busy so I try to cancel it, but it never cancels. Here are some excerpts from my code.
The lstFileList_Populate:

    Private Sub lstFileList_Populate(ByVal strFileFilters As String)
         BackgroundWorker1.WorkerReportsProgress = True
         If (BackgroundWorker1.IsBusy) Then
             BackgroundWorker1.CancelAsync()
             While BackgroundWorker1.CancellationPending
                 Threading.Thread.Sleep(1000)
             End While
         End If
         BackgroundWorker1.RunWorkerAsync()
     End Sub

The Backgroundworker1_Dowork:

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        ' Bunch of variables defined here for the actual work

         If BackgroundWorker1.CancellationPending = True Then
             e.Cancel = True
             BackgroundWorker1.Dispose()
         Else
             ' Since code was never exiting I put this second check for CancellationPending here,
             ' and again in the for loop below but I believe it's not necessary.
             If BackgroundWorker1.CancellationPending = True Then
                 e.Cancel = True
                 BackgroundWorker1.Dispose()
             Else
                 For Each strAFileName In My.Computer.FileSystem.GetFiles(Directory.GetCurrentDirectory())
                     If BackgroundWorker1.CancellationPending = True Then
                         e.Cancel = True
                         BackgroundWorker1.Dispose()
                         Exit Sub
                     End If
                     ' The evaluation of each file gets done here in a rather long section of code
             End If
         End If
End Sub

So when the lstFileList_Populate gets called the second time the code will stay in this while loop
While BackgroundWorker1.CancellationPending
    Threading.Thread.Sleep(1000)
End While
and will never exit and, of course, if I take out the above code I get the error message that the background worker is busy. What am I doing wrong????

P.S. BTW, I don't have any training in VB or VB.net other than what I've picked up online and trained myself. I've written a few programs in VB and this is my first crack at .net so my knowledge is limited. I have spent hours researching this, but it still eludes me.

NiL
  • 1
  • 2
  • I don't know if it'll make any difference, but you should use the [`Directory.EnumerateFiles Method`](https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratefiles) instead of `My.Computer.FileSystem.GetFiles` - the latter gets all the files in one go, so the program has to wait, whereas the former gets one filename at a time for you. – Andrew Morton Aug 13 '22 at 18:43
  • 1
    Those `BackgroundWorker1.Dispose()` statements don't look right: `Return` is the usual way of exiting a method. – Andrew Morton Aug 13 '22 at 18:47
  • I commented out the Dispose() and added the return instead, but it still won't stop. I put the Dispose back in along with the return and still won't stop. – NiL Aug 13 '22 at 18:54
  • Is the BGW successfully reporting its progress? That would give you something to see what it's doing. – Andrew Morton Aug 13 '22 at 19:18
  • I have some code to display the BGW progress, but since the application freezes I can't see the application UI so I can't tell what's going on. – NiL Aug 13 '22 at 19:28
  • Have you tried the change from my first comment? It could be that the BGW is temporarily busy doing the GetFiles so it hasn't progressed to the body of the loop. – Andrew Morton Aug 13 '22 at 19:30
  • I don't believe that's the problem since the directories I'm working on have very few files, which without the BGW the files get listed in one second. But since you were kind enough to take the time to suggest possible solutions I did go ahead and make the change. It did not help. The BGW still will not cancel/stop and the app gets stuck in the CancellationPending loop. – NiL Aug 14 '22 at 13:17
  • Instead of using `Threading.Thread.Sleep(1000)` you could start a timer which uses the OnTick handler to check, say every 100 ms, if the BGW is busy and if not then start the BGW again. That way the UI would remain responsive. – Andrew Morton Aug 14 '22 at 17:38
  • (Your comment "the directories I'm working on have very few files" doesn't seem to match up with "Things work fine unless a directory has many JPG files" from the question.) – Andrew Morton Aug 14 '22 at 17:40
  • 1
    Very interesting Andrew. I didn't think your timer suggestion would work, and it did not as far as allowing the UI to remain responsive. But I modified the lstFileList_Populate routine and commented out the while loop, added a new timer and started it. In the timer ticker I added logic to start BGW if it's not busy. That's all I did. Now the BGW cancels immediately when I change directory. I know because for debug I have msgbox in BGW complete and cancel routines and the cancel pops up immediately. I wonder why that is. This would be a good workaround. Thx much. – NiL Aug 14 '22 at 18:07

1 Answers1

-1

OK so here's the solution. I took out the timer that was suggested in the last comment and made one change to my code and things are working normally. After using the timer it appeared to me that when I was getting in the while loop below that Threading.Thread.Sleep(1000) was actually putting the BGW thread to sleep and was keeping it from cancelling it's operation. So I replaced it with Application.DoEvents() and BGW cancels right away. Here's the new code with comment:

    Private Sub lstFileList_Populate(ByVal strFileFilters As String)
     BackgroundWorker1.WorkerReportsProgress = True
     If (BackgroundWorker1.IsBusy) Then
         BackgroundWorker1.CancelAsync()
         While BackgroundWorker1.CancellationPending
' Thread sleep keeps BGW from canceling it's operation so instead use app doevent.
'                 Threading.Thread.Sleep(1000)
                 Application.DoEvents()
             End While
         End If
         BackgroundWorker1.RunWorkerAsync()
     End Sub

Many thanks for all the help and guidance.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
NiL
  • 1
  • 2
  • 1
    That could be a case of out of the frying pan and into the fire—here's an explanation of why Application.DoEvents() can cause unforeseen problems: [Use of Application.DoEvents()](https://stackoverflow.com/a/5183623/1115360) *et seq*. – Andrew Morton Aug 15 '22 at 16:53