简体   繁体   English

WebBrowser控件延迟加载完整的HTML

[英]WebBrowser Control delays loading full HTML

I'm not new to programming but am new to using WebBrowser controls in C# WinForm apps. 我对编程并不陌生,但是对在C#WinForm应用程序中使用WebBrowser控件并不陌生。

I have two WebBrowser controls that I dynamically load onto a form. 我有两个WebBrowser控件,它们可以动态加载到表单上。 The first navigates to a URL and upon completion I loads it's DocumentText into an HtmlAgilityPack document. 第一个导航到URL,完成后将其DocumentText加载到HtmlAgilityPack文档中。 I use XPath to parse some links that are then passed to the second browser control. 我使用XPath解析一些链接,然后将这些链接传递给第二个浏览器控件。 Everything works fine until after the second browser control loads. 一切正常,直到第二个浏览器控件加载完毕。 Its .DocumentText is less than 700 bytes long. 其.DocumentText的长度小于700个字节。 If I bypass the rest of the routine and return to the screen, the correct and full page is displayed in the second control, however I can't get that to happen inside the routine. 如果我绕过例程的其余部分并返回到屏幕,则第二个控件中将显示正确且完整的页面,但是我无法在例程中执行此操作。 The bare bones of the code is as follows. 代码的基本内容如下。

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;
    }
}

I created a test button on the form so that after the routine had returned to the screen I could click it and check what the second browser was up to. 我在表单上创建了一个测试按钮,以便例程返回到屏幕后,我可以单击它并检查第二个浏览器的功能。

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

Upon clicking the button the second browser's .DocumentText length was correct (about 130K+), but I don't see a way to get it to return that in the middle of the routine. 单击该按钮后,第二个浏览器的.DocumentText长度是正确的(大约130K +),但是我没有找到一种方法来使它在例程的中间返回。 As you can see in the commented out code I did a test to see if Update() would help, but it stays forever in the loop. 正如您在注释掉的代码中看到的那样,我进行了测试以查看Update()是否会有所帮助,但它永远存在于循环中。

Does anyone know of a way for it to finish loading without returning to the screen? 有人知道它可以完成加载而无需返回屏幕的方法吗?

Any help would surely be appreciated. 任何帮助都将不胜感激。

Thanks 谢谢

My guess is, on the second iteration of the for loop the tcs2.Task is already in completed state, so await returns immediately and you continue processing the document which hasn't been loaded yet. 我的猜测是,在for循环的第二次迭代中, tcs2.Task已经处于完成状态,因此await立即返回,您将继续处理尚未加载的文档。 The simplest way to fix this is to create tcs2 as well as documentCompletedHandler2 inside the for loop. 解决此问题的最简单方法是在for循环内创建tcs2documentCompletedHandler2

You cannot use Thread.Sleep, you need to keep pumping messages. 您不能使用Thread.Sleep,您需要保持泵送消息。 It's tempting to use DoEvents but that'd be also wrong. 使用DoEvents很诱人,但这也是错误的。 Checking this for some fresh ideas. 检查一下一些新的想法。 – Noseratio 11 hours ago – Noseratio 11小时前

then try to replace the Thread.Sleep call with await Task.Delay(TimeSpan.FromMilliseconds(500)) so that the main thread is free to do whatever webbrowser2 needs it to – vadim 9 hours ago 然后尝试用等待Task.Delay(TimeSpan.FromMilliseconds(500))替换Thread.Sleep调用,以便主线程可以自由执行webbrowser2所需的任何操作– vadim 9小时前

This actually does work. 这确实有效。 I don't know if maybe their AJAX server was slow last night or what the problem was, but I revisited all of these suggestions again today and this one works after about 1.5 seconds. 我不知道他们的AJAX服务器昨晚是否运行缓慢,或者问题出在哪里,但是我今天再次回顾了所有这些建议,并且大约1.5秒钟后,这个建议就可以工作了。 Thanks for all the help! 感谢您的帮助!

I would mark as answer but it wasn't posted as one. 我会将其标记为答案,但并未发布为答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM