reread content of webbrowser window/wait for user input

元气小坏坏 提交于 2019-11-26 22:27:26

问题


In my program I want to give 2 input-fields within a webbrowser-window a value and then wait for the user to click a login button. After this, I want the program to break out of the loop when the screen contents "Welcome!" (which it contains after logging in).

But now the problem: When the values for username and password are set, the do-loop starts instantly. So even if I click the login-button, the loop still contains the content of the webpage before the button was clicked and it will loop forever.

How can I solve this? I thought about two ways so far:

  1. Reread the html code after button clicked so the "Welcome!" will be inside the code and then the loop will break, or
  2. Wait for the user to press the login-button.

But in both ways I have no real idea how to solve it.

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()

I noticed the problem when I tried to put the html code in a message box. It just contained the 'old' code.

Thanks in advance


回答1:


The golden rule of WinForms is: NEVER, EVER use Application.DoEvents() to keep your UI responsive! If you need to use it then you are almost always doing something wrong (see: Keeping your UI Responsive and the Dangers of Application.DoEvents).

Heavy operations should never be done on the UI thread, but in a background thread. There are multiple ways of taking the work of the UI, for instance Tasks, Threads or using the BackgroundWorker.

HOWEVER in this case, you don't even need a loop. The WebBrowser has got a DocumentCompleted event that is raised every time a page (or an iframe inside the page) has loaded completely. Use that to know when to execute your code.

Having that said, here's how you'd migrate it to 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.

Here's a little test project: http://www.mydoomsite.com/sourcecodes/WebBrowser_WaitForUserInteraction.zip


Ultimately, your entire code can be changed to:

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.

Alternatively

...if you think it's too messy having lambdas everywhere, you can fall back to using regular methods:

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


来源:https://stackoverflow.com/questions/42363789/reread-content-of-webbrowser-window-wait-for-user-input

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