如何创建一个不会停止加载 Web 浏览器的等待计时器?



这是这种情况:

  • 我在VB .NET项目中有一个Web浏览器
  • 我在脸书上登录
  • 我必须等待页面/javascript输出完成加载

我想设置一个以秒为单位的等待计时器,该计时器不会停止浏览器的加载。

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

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

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

一个好的经验法则是:任何利用Application.DoEvents()的解决方案在99.9%的时间内都是糟糕的解决方案

有关DoEvents()为何如此糟糕的更多信息,请参阅:保持 UI 响应和 Application.DoEvents 的危险

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


WebBrowser控件没有使用DoEvents()而是有一个名为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 表达式动态:

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 表达式解决方案的好处是,在执行例如网页自动化时,添加和删除多个处理程序要容易得多。


编辑:

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

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

在下面的示例中,我将计时器的时钟周期设置为 250 毫秒,因此它将每秒检查元素大约 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

最新更新