如何创建一个不停止加载WebBrowser的等待计时器?

时间:2018-01-05 09:16:43

标签: .net vb.net webbrowser-control

情况就是这样:

  • 我在VB .NET项目中有一个webBrowser
  • 我在Facebook上登录
  • 我必须等待页面/ javascript输出完成加载

我想在几秒钟内设置一个等待计时器,不会停止加载浏览器。

此解决方案似乎不起作用:

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

1 个答案:

答案 0 :(得分:2)

您应该 永远, 使用Application.DoEvents()以保持您的用户界面响应!这样做是 非常糟糕的做法 ,并且可能会发生很多意想不到的事情,除非它被正确使用(在大多数情况下它并非如此)

一个好的经验法则是:任何使用Application.DoEvents()的解决方案在 错误解决方案 的99.9%的时间内。

有关DoEvents()如此糟糕的原因的详情,请参阅:Keeping your UI Responsive and the Dangers of Application.DoEvents

我知道这一切看起来有点极端,但我真的不能强调这一点。很多人今天仍在使用DoEvents()因为它已经通过一些旧的论坛和Stack Overflow帖子传播,但实际上使用它并不是很好的编程习惯,因为它几乎总是使用不正确。

DoEvents()控件不是使用WebBrowser,而是有一个名为DocumentCompleted的事件,每次页面(或页面的子部分,例如iframe)都会引发该事件满载。

该事件可以静态订阅:

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

...或动态使用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/")

Lambda Expression解决方案的优点在于,在执行网页自动化时,使用它来添加和删除多个处理程序要容易得多。

修改

如果您尝试执行自动化,我建议您使用Lambda解决方案。这样,您可以更加动态地添加和删除DocumentCompleted事件的处理程序,具体取决于您需要执行的操作。

要等待具有指定文本的元素出现,您可以启动一个迭代所有元素的计时器,并在每次滴答时检查它们InnerText

在下面的示例中,我将定时器的滴答间隔设置为250 ms,因此它将每秒检查元素大约4次。您可以根据需要进行调整,但尽量不要使用太小的延迟,否则会增加CPU使用率。

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