WebBrowser控件延迟加载完整的HTML

时间:2015-02-08 08:14:08

标签: c# winforms webbrowser-control

我不是新编程,但我很擅长在C#WinForm应用程序中使用WebBrowser控件。

我有两个动态加载到表单上的WebBrowser控件。第一个导航到URL,完成后我将它的DocumentText加载到HtmlAgilityPack文档中。我使用XPath来解析一些链接,然后传递给第二个浏览器控件。一切正常,直到第二个浏览器控件加载后。它的.DocumentText长度不到700个字节。如果我绕过剩下的例程并返回到屏幕,则在第二个控件中显示正确的完整页面,但是我无法在例程中进行此操作。代码的基本内容如下。

private WebBrowser webBrowser = new WebBrowser();
private WebBrowser webBrowser2 = new WebBrowser();
private TaskCompletionSource<bool> tcs = null;
private TaskCompletionSource<bool> tcs2 = null;
private string lastnav = "";
private string lastMessage = "";

private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
    lastnav = e.Url.ToString();
    this.txtNavigated.Text += e.Url.ToString() + "\r\n\r\n";
    if (webBrowser.Document != null && webBrowser.Document.Cookie != null)
        this.txtNavigated.Text += webBrowser.Document.Cookie + "\r\n\r\n";
    this.txtNavigated.Update();
}

private async void TryNavigate(string url)
    webBrowser.Location = new System.Drawing.Point(12, 226);
    webBrowser.Size = new System.Drawing.Size(1070,100);
    webBrowser2.Location = new System.Drawing.Point(12, 327);
    webBrowser2.Size = new System.Drawing.Size(1070, 100);

    this.Controls.Add(webBrowser);
    this.Controls.Add(webBrowser2);

    tcs = new TaskCompletionSource<bool>();
    WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (sender2, e2) => tcs.TrySetResult(true);
    WebBrowserNavigatingEventHandler docNavigatingHandler = webBrowser_Navigating;

    try
    {
        Uri baseUri = new Uri("https://www.labcorp.com/wps/portal/provider/testmenu");
        Uri newUri = null;
        webBrowser.DocumentCompleted += documentCompletedHandler;
        webBrowser.Navigating += docNavigatingHandler;
        try
        {
            webBrowser.Navigate(baseUri.AbsoluteUri);
            await tcs.Task;
        }
        catch (WebException webex) {
            lastMessage = webex.Message;
        }
        catch (Exception ex)
        {
            lastMessage = ex.Message;
        }
        finally
        {
            webBrowser.DocumentCompleted -= documentCompletedHandler;
        }
        webBrowser2.Navigate("localhost");
        webBrowser2.Document.Cookie = webBrowser.Document.Cookie;
        webBrowser2.Navigating += docNavigatingHandler;
        webBrowser2.DocumentCompleted += documentCompletedHandler2;

        HtmlAgilityPack.HtmlDocument azlinks = new HtmlAgilityPack.HtmlDocument();
        azlinks.LoadHtml(webBrowser.DocumentText);
        // get A - Z
        var azlinkNodes = azlinks.DocumentNode.SelectNodes("//div[@class='searchDiv']/table/tr/td/a");
        if (azlinkNodes != null)
        {
            tcs2 = new TaskCompletionSource<bool>();
            WebBrowserDocumentCompletedEventHandler documentCompletedHandler2 = (sender2, e2) => tcs2.TrySetResult(true);
            if (Uri.TryCreate(baseUri, azlinkNodes[0].Attributes["href"].Value, out newUri))
            {
                try
                {
                    webBrowser2.Navigate(newUri);
                    await tcs2.Task;
                }
                finally
                {
                    webBrowser2.DocumentCompleted -= documentCompletedHandler2;
                }

                // **************************************************
                // will not come out of this test loop
                //while (webBrowser2.DocumentText.Length < 10000) {
                //    webBrowser2.Update();
                //    System.Threading.Thread.Sleep(500);
                //}

                MessageBox.Show("webBrowser2.DocumentText.Length = " + webBrowser2.DocumentText.Length.ToString(), "Length");
            }
        }
    }
    catch (Exception ex)
    {
        lastMessage = ex.Message;
    }
}

我在表单上创建了一个测试按钮,以便在例程返回到屏幕后,我可以单击它并检查第二个浏览器的内容。

    private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("webBrowser2.DocumentText.Length = " + webBrowser2.DocumentText.Length.ToString(), "Length");
}

点击按钮后,第二个浏览器的.DocumentText长度是正确的(大约130K +),但我没有看到让它在例程中间返回的方法。正如你在注释掉的代码中看到的那样,我做了一个测试,看看Update()是否会有所帮助,但它会永远停留在循环中。

有没有人知道如何在不返回屏幕的情况下完成加载?

任何帮助肯定会受到赞赏。

由于

2 个答案:

答案 0 :(得分:0)

我的猜测是,在for循环的第二次迭代中,tcs2.Task已经处于已完成状态,因此await立即返回,您继续处理尚未加载的文档。解决此问题的最简单方法是在tcs2循环内创建documentCompletedHandler2以及for

答案 1 :(得分:0)

你不能使用Thread.Sleep,你需要继续抽取消息。使用DoEvents很诱人,但这也是错误的。检查一下这些新想法。 - Noseratio 11小时前

然后尝试用等待Task.Delay(TimeSpan.FromMilliseconds(500))替换Thread.Sleep调用,以便主线程可以自由地做任何webbrowser2需要它 - vadim 9小时前

这确实有效。我不知道他们的AJAX服务器昨晚是否很慢或问题是什么,但我今天再次重新审视了所有这些建议,这个建议在大约1.5秒之后就可以运行了。谢谢你的帮助!

我会将其标记为答案,但并未将其作为一个发布。