How to create a waiting timer that does not stop the loading of a WebBrowser?

℡╲_俬逩灬. 提交于 2019-11-28 12:49:41

问题


This is the situation:

  • I have a webBrowser in a VB .NET project
  • I do a login on Facebook
  • I have to wait for the page / javascript output to finish loading

I want to set a waiting timer in seconds that do not stop the loading of the browser.

This solution seem not to work:

    Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
        Application.DoEvents()
    Loop

回答1:


You should NEVER, EVER use Application.DoEvents() in order to keep your UI responsive! Doing so is very bad practice and opens up the possibility of a lot of unexpected things happening, unless it is used correctly (which in most cases it isn't).

A good rule of thumb is: Any solution that utilizes Application.DoEvents() is in 99.9% of the time a bad solution.

For more information about why DoEvents() is so bad, refer to: Keeping your UI Responsive and the Dangers of Application.DoEvents.

I know all this might seem a bit extreme, but I can't really stress this enough. A lot of people are still using DoEvents() today because it has been spread via some old forum and Stack Overflow posts, but it is infact not very good programming practice to use it because it is almost always used incorrectly.


Instead of using DoEvents(), the WebBrowser control has an event called DocumentCompleted which is raised every time a page (or a sub-part of a page, such as an iframe) is fully loaded.

The event can be subscribed to either statically:

Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
    If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
        'Do stuff when the page has finished loading.
    End If
End Sub

...or dynamically using Lambda Expressions:

Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
        If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
            'Do stuff when the page has finished loading.
            'If you need to load another page and wait for it, just repeat the exact same code in here (but remember to rename the variables!).

            RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler 'Remove the event handler (if you don't want this to be called twice).
        End If
    End Sub

AddHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler

WebBrowser1.Navigate("https://www.facebook.com/")

The good thing about the Lambda Expression solution is that it is much easier to use to add and remove multiple handlers when performing for instance web page automation.


EDIT:

If you're trying to perform automation I recommend the Lambda solution. That way you can a bit more dynamically add and remove handlers of the DocumentCompleted event, depending on what you need to do.

To wait for an element with the specified text to appear, you can start a timer that iterates all the elements and check their InnerText every time it ticks.

In the example below I've set the tick interval of the timer to 250 ms, thus it will check for the element approximately 4 times per second. You can adjust this as needed, but try not to use too small delays as that will increase CPU usage.

Dim WithEvents StepTwoWaitingTimer As New Timer With {.Interval = 250}

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim StepOneHandler As WebBrowserDocumentCompletedEventHandler = _
        Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
            If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
                StepTwoWaitingTimer.Start() 'Start waiting for the required element to appear.

                RemoveHandler WebBrowser1.DocumentCompleted, StepOneHandler
            End If
        End Sub

    AddHandler WebBrowser1.DocumentCompleted, StepOneHandler

    WebBrowser1.Navigate("your URL here")
End Sub

Private Sub StepTwoWaitingTimer_Tick(sender As Object, e As EventArgs) Handles StepTwoWaitingTimer.Tick
    'Iterate each element with the "_54nh" class.
    For Each Element As HtmlElement In WebBrowser1.Document.GetElementsByClassName("_54nh")
        If Element.InnerText = "TEXTINSIDETHETAG" Then
            'Element found. Click it and stop the timer.
            Element.InvokeMember("click")
            StepTwoWaitingTimer.Stop()

            Exit For 'Stop the loop.
        End If
    Next
End Sub


来源:https://stackoverflow.com/questions/48110456/how-to-create-a-waiting-timer-that-does-not-stop-the-loading-of-a-webbrowser

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