Can I wait for a webbrowser to finish navigating, using a for loop?

喜欢而已 提交于 2019-11-27 15:14:32
noseratio

Assuming you host WebBrowser in a WinFroms application, you can do it in a loop easily and efficiently, using async/await pattern. Try this:

async Task DoNavigationAsync()
{
    TaskCompletionSource<bool> tcsNavigation = null;
    TaskCompletionSource<bool> tcsDocument = null;

    this.WB.Navigated += (s, e) =>
    {
        if (tcsNavigation.Task.IsCompleted)
            return;
        tcsNavigation.SetResult(true);
    };

    this.WB.DocumentCompleted += (s, e) =>
    {
        if (this.WB.ReadyState != WebBrowserReadyState.Complete)
            return;
        if (tcsDocument.Task.IsCompleted)
            return;
        tcsDocument.SetResult(true); 
    };

    for (var i = 0; i <= 21; i++)
    {
        tcsNavigation = new TaskCompletionSource<bool>();
        tcsDocument = new TaskCompletionSource<bool>();

        this.WB.Navigate("http://www.example.com?i=" + i.ToString());
        await tcsNavigation.Task;
        Debug.Print("Navigated: {0}", this.WB.Document.Url);
        // navigation completed, but the document may still be loading

        await tcsDocument.Task;
        Debug.Print("Loaded: {0}", this.WB.DocumentText);
        // the document has been fully loaded, you can access DOM here
    }
}

Now, it's important to understand that DoNavigationAsync executes asynchronously. Here's how you'd call it from Form_Load and handle the completion of it:

void Form_Load(object sender, EventArgs e)
{
    var task = DoNavigationAsync();
    task.ContinueWith((t) =>
    {
        MessageBox.Show("Navigation done!");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

I've answered a similar question here.

You don't have to use another void function. Simply use a lambda like so:

webB.DocumentCompleted += (sender, e) =>
{
    // your post-load code goes here
};

Use this while loop inside the for loop.

while (webB.ReadyState != tagREADYSTATE.READYSTATE_COMPLETE)
            {
               Thread.Sleep(500);
            }

This waits until the WebBrowser loads the page completely.

To wait in a thread you can do something like this

 System.Threading.Thread.Sleep(2000); //waits 2 seconds

Unfortunately, it is not linked up with the navigation finish time.

Avi Turner

The proper way is to use events.
In your loop, how can you know that that the navigation have completed? maybe you are out of the loop but it is only half way through...

Also, looping while waiting is called Busy waiting and is CPU expensive.

In order to be notified when page is ready, and in the meanwhile keep CPU available for other stuff, use events as @Jashaszun suggested:

void YourFunction()
{
  //Do stuff...
  webB.DocumentCompleted += (sender, e) =>
  {
      //Code in here will be triggered when navigation is complete and document is ready
  };
  webB.Navigate(URL);
  //Do more stuff...
}

Try using tasks like this:

for (i = 0; i <= 21; i++)
{
   Task taskA = Task.Factory.StartNew(() => webB.Navigate(URL));
   taskA.Wait();
}

Hope I helped.

Bourch Mustapha
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        WebBrowser1.Navigate("stackoverflow.com/")

    End Sub

    Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted

    ------yourcode------

    End Sub

End Class
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!