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

后端 未结 1 1783
名媛妹妹
名媛妹妹 2020-12-22 07:23

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 f
相关标签:
1条回答
  • 2020-12-22 07:44

    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
    
    0 讨论(0)
提交回复
热议问题