перечитать содержимое окна веб-браузера / дождаться ввода пользователя

В моей программе я хочу указать 2 поля ввода в окне веб-браузера со значением, а затем дождаться, когда пользователь нажмет кнопку входа в систему. После этого я хочу, чтобы программа вырвалась из цикла, когда на экране появится надпись «Добро пожаловать!» (который он содержит после входа в систему).

Но теперь проблема: когда значения для имени пользователя и пароля установлены, цикл выполнения запускается мгновенно. Таким образом, даже если я нажму кнопку входа в систему, цикл все равно будет содержать содержимое веб-страницы до нажатия кнопки, и он будет зацикливаться навсегда.

Как я могу это решить? До сих пор я думал о двух способах:

  1. Перечитайте html-код после нажатия кнопки, чтобы "Добро пожаловать!" будет внутри кода и тогда цикл разорвется, или
  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-код в окно сообщения. Он просто содержал «старый» код.

заранее спасибо


person neverlucky    schedule 21.02.2017    source источник


Ответы (1)


Золотое правило WinForms: НИКОГДА, НИКОГДА не используйте Application.DoEvents(), чтобы пользовательский интерфейс оставался отзывчивым! Если вам нужно его использовать, вы почти всегда делаете что-то не так (см.: Поддержание адаптивности пользовательского интерфейса и опасности Application.DoEvents) .

Тяжелые операции никогда не должны выполняться в потоке пользовательского интерфейса, а должны выполняться в фоновом потоке. Существует несколько способов выполнения работы пользовательского интерфейса, например Задачи, потоки или с помощью BackgroundWorker.

ОДНАКО в этом случае вам даже не нужен цикл. WebBrowser имеет DocumentCompleted событие, которое вызывается каждый раз, когда страница (или 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.

Альтернативно

... если вы считаете, что лямбды везде слишком беспорядочны, вы можете вернуться к использованию обычных методов:

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
person Visual Vincent    schedule 21.02.2017
comment
Я пробовал, но теперь программа просто пропускает весь блок кода. Я добавил MsgBox в строку «Поместите код», но он просто не отображается. - person neverlucky; 21.02.2017
comment
@neverlucky : Это странно... Позвольте мне попробовать это через некоторое время, я написал это со своего телефона. - person Visual Vincent; 21.02.2017
comment
@neverlucky: Действительно ли страница перенаправляет вас куда-то еще после нажатия кнопки входа? - person Visual Vincent; 21.02.2017
comment
@neverlucky Не могли бы вы обновить вопрос, добавив еще немного кода? Это работает совершенно нормально для меня. - person Visual Vincent; 21.02.2017
comment
@neverlucky: вы закрываете WebBrowserWindow до завершения загрузки страницы. Вы должны переместить вызовы WebBrowserWindow.Close() и Me.Close() в то же место, что и окно сообщения. - person Visual Vincent; 21.02.2017
comment
@neverlucky: все после AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler будет выполнено почти сразу, а это означает, что формы закроются еще до того, как пользователь получит время для взаимодействия. -- И снова избавьтесь от всех вызовов Application.DoEvents() и их циклов. Весь ваш код можно поместить в два обработчика DocumentCompleted. Я обновлю свой ответ этим. - person Visual Vincent; 21.02.2017
comment
@neverlucky: если при выполнении кода ничего не происходит, попробуйте удалить WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") из оператора If. - person Visual Vincent; 21.02.2017
comment
Спасибо большое, теперь (почти) работает! Теперь программа ждет нажатия кнопки, но по-прежнему не реагирует на If WebBrowserFenster.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Welcome") Then (это я вставил туда, где был MsgBox(it works)). Я также удаляю строку, потому что программа ждет, пока страница полностью загрузится, но все же, почему она не распознает новый исходный код html? - person neverlucky; 21.02.2017
comment
@neverlucky: если сайт построен с использованием фреймов, то исходный код для него будет только <iframe src="otherpage.html"></iframe>, вы не увидите исходный код в iframe. Вместо этого лучше проверить что-то вроде If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("iframe src="otherpage.html"). - person Visual Vincent; 21.02.2017
comment
@neverlucky: Кроме того, звонок .ToString, который у вас есть на InnerHtml, просто лишний. InnerHtml уже является строкой, поэтому ее не нужно снова преобразовывать. :) - person Visual Vincent; 21.02.2017
comment
@neverlucky: Рад, что смог помочь! Удачи с вашим проектом! - person Visual Vincent; 21.02.2017