1

I have a loop that goes through a number of values. With every value iterated, a page is loaded in a webbrowser control (with the value passed as a parameter) and when the page is loaded and read, the loop should go to the next value in the list and continue until all values are processed. I need a way to pause the procedure while the website is loading asynchronously and then resume once the page loading/reading process is complete.

The way I am doing is by using something like this, where "ReadingInProgress" is a global variable:

      ReadingInProgress = True
      wb.Navigate("http://mywebsite.com/mypage.aspx" & c)

      While ReadingInProgress
        Application.DoEvents()
      End While

The "DocumentCompleted" event of the webrowser control set "ReadingInProgress" to false which causes the while loop to exit and resume the procedure. This works, but I realize that it puts a strain on the CPU. Is there a better, less CPU intensive way to do this?

Thanks!

Osprey
  • 1,523
  • 8
  • 27
  • 44
  • Instead of waiting in the loop, why not just move the code that happens after the loop to the DocumentCompleted event handler, instead? – Steven Doggart Aug 19 '13 at 14:21
  • I cannot do that because code does not happen after the loop, but inside the loop. There is already some code that is executed on DocumentCompleted of the webbrowser. I want the loop to wait until that is executed before moving to the next item in the list. In other words, I need to change the .Navigate command to a synchronous command. – Osprey Aug 20 '13 at 07:56
  • It's still not clear why you can't call the `Navigate` method from the `DocumentCompleted` event handler. – Steven Doggart Aug 20 '13 at 10:31
  • I have a list of different parameters that I need to pass to the same page. I use a loop to iterate through each parameter and feed it to the page using the `wb.Navigate` command. I need to stop the loop while waiting for the `DocumentCompleted` to complete before firing another `wb.Navigate` command. – Osprey Aug 20 '13 at 12:40

2 Answers2

1

One way would be to take whatever is after the loop, and put that in the handler for the control's DocumentComplete event.

Another would be to have this code run in another thread. It'd start the navigation and then wait on a semaphore, EventWaitHandle, or other waitable object that the DocumentComplete handler sets. Something like this:

private sem as Semaphore
private withevents wb as WebBrowser

...

sub DoWork()
    for each url as String in urls
        ' You'll almost certainly need to do this, since this isn't the UI thread
        ' anymore.
        wb.invoke(sub() wb.Navigate(url))
        sem.WaitOne()

        ' wb is done

    next
end sub

sub wb_DocumentComplete(sender as obj, args as WebBrowserDocumentCompletedEventArgs) _
handles wb.DocumentCompleted
    sem.Release()
end sub

...

dim th as new Thread(addressof me.DoWork)
th.Start()

Either way, since you're not taking up the UI thread anymore, you don't have to worry about Application.DoEvents().

cHao
  • 84,970
  • 20
  • 145
  • 172
  • I am already doing that. The bulk of the operation is done in the DocumentComplete and it does set a semaphore (which the while loop waits for). What I need is a way to pause the original loop (the one that calls wb.navigate multiple times) to wait for the DocumentComplete to actually complete before issuing another web.navigate command. I need to turn wb.navigate into a synchronous command that ends its execution along with the end of the DocumentComplete execution. – Osprey Aug 20 '13 at 08:10
  • If `DocumentComplete` sets the semaphore, and you're doing this outside of the UI thread, then you already have stuff ready to go. `for each url in urls : wb.navigate(url) : sem.WaitOne() : (do stuff) : next` . `sem`, of course, being the semaphore that the `DocumentComplete` handler sets. – cHao Aug 20 '13 at 13:07
1

I've recently answered a similar question. The solution is in C#, but you can use Async/Await in VB.NET in a very similar way. Using this technique, you would get a natural flow of execution for your code (DocumentComplete event is encapsulated as Task).

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    According to the link you provided, the Await command was added to VS2012. Unfortunately I am using VS2010. – Osprey Aug 20 '13 at 08:07
  • If you cannot refactor your code to use events and it has to be linear like in your question, at least put `Sleep(200)` after `Application.DoEvents()`. This is still a very bad model. At least, you should disable the UI to mitigate code reentracy. – noseratio Aug 20 '13 at 09:36
  • @Osprey, does your application have any UI windows? If so, maybe there's a better way to get what you want, using a modal dialog instead of your `Application.DoEvents()` loop. – noseratio Aug 20 '13 at 11:12
  • 1
    Yes, it does have a UI window containing the web browser control. Are you suggesting loading a modal dialog with the webbrowser control in it and then close the dialog from the DocumentComplete event? Didn't think about that and I think it will probably work! Thanks! :) – Osprey Aug 20 '13 at 12:37
  • Yes, that's exactly what I meant :) **-- ops, not exactly**. You could keep your WebBrowser where it is now. You'd create a simple form to use as modal dialog (with a friendly "please wait..." message), show it with `ShowDialog` after calling `Navigate` and close it from your `DocumentComplete` (instead of setting `ReadingInProgress`). – noseratio Aug 20 '13 at 12:44
  • @Osprey, sorry that's not exactly what I meant, although similar. I just edited my comment above to clarify it. I think it may work the other way around as you proposed - a WB in a dialog - but then you'd create an new instance of WB each time you need to navigate it. – noseratio Aug 20 '13 at 12:52
  • 1
    I used the method you suggested which was even simpler than what I had understood initially. I simply had to add a dummy "please wait" form and load it with show dialog instead of the While loop. Then close it in the `DocumentComplete` event. It works like a charm! :) – Osprey Aug 20 '13 at 13:32
  • Glad it worked out! I do believe this method is a little more CPU (and user!) fiendly :) – noseratio Aug 20 '13 at 13:36