重新读取网络浏览器 window/wait 的内容以供用户输入

reread content of webbrowser window/wait for user input

在我的程序中,我想在 webbrowser-window 中给 2 个输入字段一个值,然后等待用户单击登录按钮。在此之后,我希望程序在屏幕内容 "Welcome!"(登录后包含)时跳出循环。

但现在的问题是:设置用户名和密码的值后,do-loop 立即开始。所以即使我点击登录按钮,循环仍然包含点击按钮之前的网页内容,它将永远循环。

我该如何解决这个问题?目前我想过两种方法:

  1. 点击按钮后重新阅读 html 代码,这样 "Welcome!" 就会在代码内部,然后循环就会中断,或者
  2. 等待用户按下登录按钮。

但这两种方式我都不知道如何解决。

WebBrowserWindow.WebBrowser1.Navigate("[...]")

Do
    If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
        If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then Exit Do
    End If
    Application.DoEvents()
Loop

If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then
    WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
    WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
    Application.DoEvents()

    Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
                                                                                  If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
                                                                                      RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
                                                                                      'Put the code that should be executed when the user has logged in here.
                                                                                      MsgBox("it works")
                                                                                  End If
                                                                              End Sub

    AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler 
End If

WebBrowserWindow.Close()
Me.Close()

我在尝试将 html 代码放入消息框中时注意到了这个问题。它只包含 'old' 代码。

提前致谢

WinForms 的黄金法则是:永远,永远 使用 Application.DoEvents() 来保持你的 UI 响应!如果你需要使用它,那么你几乎总是在做错事(参见:Keeping your UI Responsive and the Dangers of Application.DoEvents)。

绝不应在 UI 线程上执行繁重的操作,而应在后台线程中执行。有多种获取 UI 作品的方法,例如 Tasks, Threads or using the BackgroundWorker.

HOWEVER 在这种情况下,您甚至不需要循环。 WebBrowser 有一个 DocumentCompleted event ,每次页面(或页面内的 iframe )完全加载时都会引发。使用它来了解何时执行您的代码。

话虽如此,以下是将其迁移到 DocumentCompleted 的方法:

WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)

Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
        If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
            RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
            'Put the code that should be executed when the user has logged in here.
        End If
    End Sub

AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler

'Any code put here won't wait for the user to log in, it wil be executed pretty much immediately.

这是一个小测试项目:http://www.mydoomsite.com/sourcecodes/WebBrowser_WaitForUserInteraction.zip


最终,您的整个代码可以更改为:

WebBrowserWindow.WebBrowser1.Navigate("[...]")

Dim FirstDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
    Sub()
        'Check if:
        ' - The web browser has finished loading.
        ' - WebBrowser1.Document is not Null.
        ' - WebBrowser1.Document.Body is not Null.
        ' - WebBrowser1.Document.Body.InnerHtml is not Null.
        ' - WebBrowser1.Document.Body.InnerHtml contains "Login".
        If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
            WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
             WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
              WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
               WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then

            'The code put in here will execute when the page loads the first time, and the above conditions are met.

            'We are at the login page. Enter the credentials.
            WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
            WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)

            Dim SecondDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
                Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)

                    If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
                        RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler

                        'The code put in here will be executed after the user has pressed "Login".
                        MsgBox("it works")
                        WebBrowserWindow.Close()
                        Me.Close()

                    End If

                End Sub

            AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler 'Add the second DocumentCompleted event handler.
            RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler 'Remove the first DocumentCompleted event handler.

        End If
    End Sub

AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler

'Again, any code put here will execute almost immediately, thus NOT waiting for the page to load.

或者

...如果您认为到处都是 lambda 太麻烦,您可以退回到使用常规方法:

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    WebBrowserWindow.WebBrowser1.Navigate("[...]")
    AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted
End Sub

Private Sub WebBrowserWindow_FirstDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
    'Check if:
    ' - The web browser has finished loading.
    ' - WebBrowser1.Document is not Null.
    ' - WebBrowser1.Document.Body is not Null.
    ' - WebBrowser1.Document.Body.InnerHtml is not Null.
    ' - WebBrowser1.Document.Body.InnerHtml contains "Login".
    If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
        WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
         WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
          WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
           WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then

        'We are at the login page. Enter the credentials.
        WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
        WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)

        AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted 'Add the second DocumentCompleted event handler.
        RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted 'Remove the first DocumentCompleted event handler.

    End If
End Sub

Private Sub WebBrowserWindow_SecondDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
    If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
        RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted

        'Put the code that should be executed when the user has logged in here.
        MsgBox("it works")
        WebBrowserWindow.Close()
        Me.Close()

    End If
End Sub