从外部的DoEvents WebBrowser控件获取的readyState控件、DoEvents、WebBrowser、readyState

2023-09-02 21:53:23 作者:初闻不知曲中意

这已经awnsered多次在这里和在其他网站和它的工作,但我想的想法,其他方式:

This has been awnsered many times here and at other sites and its working, but I would like ideas to other ways to:

获得的readyState =完全使用导航或交后,不使用,因为它的所有利弊的DoEvents。

get the ReadyState = Complete after using a navigate or post, without using DoEvents because of all of its cons.

我也想指出,使用DocumentComplete事件woud没有任何帮助,因为我不会是只有一个网页浏览上,但一个又一个这样的。

I would also note that using the DocumentComplete event woud not help here as I wont be navigating on only one page, but one after another like this.

wb.navigate("www.microsoft.com")
//dont use DoEvents loop here
wb.Document.Body.SetAttribute(textbox1, "login")
//dont use DoEvents loop here
if (wb.documenttext.contais("text"))
//do something

的方式是今天使用的DoEvents其工作。我想知道,如果任何人有一个适当的方式等待的浏览器方法的异步调用仅然后继续进行逻辑的其余部分。只是为了它的缘故。

The way it is today its working by using DoEvents. I would like to know if anyone have a proper way to wait the async call of the browser methods to only then proceed with the rest of the logic. Just for the sake of it.

在此先感谢。

推荐答案

下面是一个基本的WinForms应用程序code,说明如何异步等待 DocumentCompleted 事件,使用异步/计谋。它定位到多个页面,一个接一个。一切都走的是主UI线程上进行。

Below is a basic WinForms app code, illustrating how to wait for the DocumentCompleted event asynchronously, using async/await. It navigates to multiple pages, one after another. Everything is taking place on the main UI thread.

而不是调用的 this.webBrowser.Navigate(URL),它可能会模拟表单按钮点击,触发后风格的导航。

Instead of calling this.webBrowser.Navigate(url), it might be simulating a form button click, to trigger a POST-style navigation.

webBrowser.IsBusy 异步循环逻辑是可选的,它的目的是为了负责(非确定性)为页面的动态AJAX code后可能发生的window.onload 事件。

The webBrowser.IsBusy async loop logic is optional, its purpose is to account (non-deterministically) for the page's dynamic AJAX code which may take place after window.onload event.

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WebBrowserApp
{
    public partial class MainForm : Form
    {
        WebBrowser webBrowser;

        public MainForm()
        {
            InitializeComponent();

            // create a WebBrowser
            this.webBrowser = new WebBrowser();
            this.webBrowser.Dock = DockStyle.Fill;
            this.Controls.Add(this.webBrowser);

            this.Load += MainForm_Load;
        }

        // Form Load event handler
        async void MainForm_Load(object sender, EventArgs e)
        {
            // cancel the whole operation in 30 sec
            var cts = new CancellationTokenSource(30000);

            var urls = new String[] { 
                    "http://www.example.com", 
                    "http://www.gnu.org", 
                    "http://www.debian.org" };

            await NavigateInLoopAsync(urls, cts.Token);
        }

        // navigate to each URL in a loop
        async Task NavigateInLoopAsync(string[] urls, CancellationToken ct)
        {
            foreach (var url in urls)
            {
                ct.ThrowIfCancellationRequested();
                var html = await NavigateAsync(ct, () => 
                    this.webBrowser.Navigate(url));
                Debug.Print("url: {0}, html: n{1}", url, html);
            }
        }

        // asynchronous navigation
        async Task<string> NavigateAsync(CancellationToken ct, Action startNavigation)
        {
            var onloadTcs = new TaskCompletionSource<bool>();
            EventHandler onloadEventHandler = null;

            WebBrowserDocumentCompletedEventHandler documentCompletedHandler = delegate
            {
                // DocumentCompleted may be called several time for the same page,
                // if the page has frames
                if (onloadEventHandler != null)
                    return;

                // so, observe DOM onload event to make sure the document is fully loaded
                onloadEventHandler = (s, e) =>
                    onloadTcs.TrySetResult(true);
                this.webBrowser.Document.Window.AttachEventHandler("onload", onloadEventHandler);
            };

            this.webBrowser.DocumentCompleted += documentCompletedHandler;
            try
            {
                using (ct.Register(() => onloadTcs.TrySetCanceled(), useSynchronizationContext: true))
                {
                    startNavigation();
                    // wait for DOM onload event, throw if cancelled
                    await onloadTcs.Task;
                }
            }
            finally
            {
                this.webBrowser.DocumentCompleted -= documentCompletedHandler;
                if (onloadEventHandler != null)
                    this.webBrowser.Document.Window.DetachEventHandler("onload", onloadEventHandler);
            }

            // the page has fully loaded by now

            // optional: let the page run its dynamic AJAX code,
            // we might add another timeout for this loop
            do { await Task.Delay(500, ct); }
            while (this.webBrowser.IsBusy);

            // return the page's HTML content
            return this.webBrowser.Document.GetElementsByTagName("html")[0].OuterHtml;
        }
    }
}

如果您正在寻找这样做,从一个控制台应用程序类似的东西,这里是的的一个例子。

If you're looking to do something similar from a console app, here is an example of that.