0

I have a problem when click button 1st time, webbrowser.DocumentText always not loaded, but on 2nd or 3rd time clickings the documentText is ALWAYS loaded.

Glad if someone can advice.

my code as below:

Private Property pageready As Boolean = False

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button3.Click
        WebBrowser1.Navigate(url)
        WaitForPageLoad()
        RichTextBox1.Text = WebBrowser1.DocumentText
        Msgbox ("Document Loaded")
    End Sub


    Private Sub WaitForPageLoad()
        AddHandler WebBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
        While Not pageready
            Application.DoEvents()
        End While
        pageready = False
    End Sub

    Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
        If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
            pageready = True
            RemoveHandler WebBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
        End If
    End Sub
Toh
  • 99
  • 2
  • 10
  • _**NEVER, EVER**_ call `Application.DoEvents()` to keep your application responsive, _**especially not**_ in a no-delay loop! Execute your code in the `DocumentCompleted` event handler and/or subscribe to the event dynamically if you must. You can utilize [**lambda expressions**](https://msdn.microsoft.com/en-us/library/bb531253.aspx) for dynamic event handlers. – Visual Vincent Dec 19 '16 at 08:06
  • Please read this: [**Keeping your UI Responsive and the Dangers of Application.DoEvents**](https://blogs.msdn.microsoft.com/jfoscoding/2005/08/06/keeping-your-ui-responsive-and-the-dangers-of-application-doevents/). – Visual Vincent Dec 19 '16 at 08:07
  • Thank you for your advise... digesting... – Toh Dec 19 '16 at 14:45
  • Your advise save my days !!! Thank you Sir !!! – Toh Dec 20 '16 at 00:40

2 Answers2

1

Task Delay till the DocumentComplete loaded is the solustion for me.

Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button3.Click
    WebBrowser1.Navigate(url)
    Await ExampleMethodAsync()
    RichTextBox1.Text = WebBrowser1.DocumentText
    Msgbox ("Document Loaded")
End Sub

Async Function ExampleMethodAsync() As Task
    ' The following line simulates a task-returning asynchronous process.  
    Await Task.Delay(1750)
End Function
Toh
  • 99
  • 2
  • 10
  • Nice job! I have a question though: Is that delay permanent or is it just a placeholder for your actual code? Because waiting for 1.75 sec will not ensure that the site is fully loaded. -- What you could do instead is to implement a [**ManualResetEvent**](http://stackoverflow.com/a/38546493/3740093) where you call `WaitOne(-1)` in the end of the task, `Reset()` in the beginning of the task and `Set()` in the `DocumentCompleted` event handler. – Visual Vincent Dec 20 '16 at 08:18
  • Indeed, you are right. Not all the time the sites are fully loaded... Digesting the ManualResetEvent suggested. Thank you so much. – Toh Dec 21 '16 at 01:00
  • Hi Sir, I am very new in programming and learn by observing examples of coding of others... try and error.. many times with limited understandings. Is it possible for you to help to incorporate ManualResetEvent /WaitOne/Reset/Set/DocumentCompleted solution onto my code... so that I can move on. Many Many thanks. toh – Toh Dec 21 '16 at 03:39
  • Of course I'll help you :). I'll post an answer when I get home later. – Visual Vincent Dec 21 '16 at 07:14
  • Thank you. Appreciate your help. – Toh Dec 21 '16 at 09:39
0

Here are two different ways you can dynamically wait for the WebBrowser to load the entire page:

  1. Extending your Async/Await method to actually wait for the page to load you can use a ManualResetEvent. The MRE functions as a door: When you call Set() you open the door, when you call Reset() you close it, and when you call WaitOne(-1) you wait by the door for it to open (if it's closed).

    Private DocumentCompletedResetEvent As New ManualResetEvent(False)
    
    Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button3.Click
        WebBrowser1.Navigate(url)
        Await ExampleMethodAsync()
        RichTextBox1.Text = WebBrowser1.DocumentText
        Msgbox("Document Loaded")
    End Sub
    
    Async Function ExampleMethodAsync() As Task
        DocumentCompletedResetEvent.Reset() 'Makes sure that the MRE is closed.
        DocumentCompletedResetEvent.WaitOne(-1) 'Waits for it to open.
    End Function
    
    Private Sub WebBrowser1_DocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
            DocumentCompletedResetEvent.Set() 'Opens the MRE.
        End If
    End Sub
    
  2. The second method adds a temporary event handler to the DocumentCompleted event. Using Lambda expressions you may create an in-line method for the event handler.

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        WebBrowser1.Navigate(TextBox1.Text)
    
        'Creates a temporary event handler.
        Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
            Sub()
                If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
                    RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler 'Removes the temporary event handler.
                    RichTextBox1.Text = WebBrowser1.DocumentText
                    Msgbox("Document Loaded")
                End If
            End Sub
        AddHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler 'Adds the temporary event handler.
    End Sub
    
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • If this solves your problem please mark it as the accepted answer by pressing the check mark on the left of my post. :) – Visual Vincent Dec 22 '16 at 00:46
  • Thank you for your code... Digesting and will keep you update. – Toh Dec 22 '16 at 05:15
  • Pls advise for Method 1 there is a green wavy underline below the code: – Toh Dec 22 '16 at 06:59
  • [Async Function ExampleMethodAsync() As Task] ... Under the ExampleMethodAsync() .... is there something missing. – Toh Dec 22 '16 at 07:00
  • What does the warning say? – Visual Vincent Dec 22 '16 at 08:52
  • Function Form1.ExampleMethodAsync() As Task ... Usage: Await ExampleMethodAsync() ...This async method lacks 'Await' operators and so will run synchronously. Consider using the 'Await' operator to await non-blocking API calls, or 'Await Task ... show potential fixes (Ctrl+.) – Toh Dec 22 '16 at 09:01
  • @Toh : Try prepending the entire `WaitOne(-1)`-line with `Await`. – Visual Vincent Dec 22 '16 at 10:22
  • @Toh : It seems you cannot await resetevents... In that case you must use my second option. – Visual Vincent Dec 23 '16 at 10:55
  • Merry Christmas, your kindness and help have blessed many. Thank you Sir. – Toh Dec 25 '16 at 00:43
  • First option is quite challenging for me to understand. The second option is much easier and it work PERFECTLY for me, however, the If and End If lines were removed. I consider my problem is solved. Thank you Very much. – Toh Dec 25 '16 at 00:54
  • @Toh : No problem! But as I said the first option won't work... Though why remove `If/End If`? It checks if the website is fully loaded, that is, if it has loaded all its sub-parts (such as `iframe`s) too. – Visual Vincent Dec 25 '16 at 01:17
  • @Toh : A Merry Christmas to you too! :) – Visual Vincent Dec 25 '16 at 01:18