C#如何在继续之前等待网页完成加载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/583897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:12:03  来源:igfitidea点击:

C# how to wait for a webpage to finish loading before continuing

c#webbrowser-control

提问by MD6380

I'm trying to create a program to clone multiple bugs at a time through the web interface of our defect tracking system. How can I wait before a page is completely loaded before I continue?

我正在尝试创建一个程序,通过我们的缺陷跟踪系统的 Web 界面一次克隆多个错误。在我继续之前,如何等待页面完全加载?

//This is pseudo code, but this should give you an idea of what I'm trying to do.  The
//actual code uses multi-threading and all that good stuff :).
foreach (string bug in bugs)
{
    webBrowser.Navigate(new Uri(url));
    webBrowser.Document.GetElementById("product").SetAttribute("value", product);
    webBrowser.Document.GetElementById("version").SetAttribute("value", version);
    webBrowser.Document.GetElementById("commit").InvokeMember("click");

    //Need code to wait for page to load before continuing.
}

采纳答案by Quintin Robinson

Try the DocumentCompleted Event

尝试 DocumentCompleted 事件

webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);

void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    webBrowser.Document.GetElementById("product").SetAttribute("value", product);
    webBrowser.Document.GetElementById("version").SetAttribute("value", version);
    webBrowser.Document.GetElementById("commit").InvokeMember("click");
}

回答by James Pogran

If you are using the InternetExplorer.Application COM object, check the ReadyState property for the value of 4.

如果您使用的是 InternetExplorer.Application COM 对象,请检查 ReadyState 属性的值是否为 4。

回答by Charlino

Check out the WatiN project:

查看WatiN 项目

Inspired by Watirdevelopment of WatiN started in December 2005 to make a similar kind of Web Application Testing possible for the .Net languages. Since then WatiN has grown into an easy to use, feature rich and stable framework. WatiN is developed in C# and aims to bring you an easy way to automate your tests with Internet Explorer and FireFox using .Net...

Watir 的启发,WatiN 于 2005 年 12 月开始开发,旨在为 .Net 语言提供类似的 Web 应用程序测试。从那时起,WatiN 已经成长为一个易于使用、功能丰富且稳定的框架。WatiN 是用 C# 开发的,旨在为您提供一种使用 .Net 使用 Internet Explorer 和 FireFox 自动化测试的简单方法......

回答by Mike

I think the DocumentCompletedevent of the WebBrowser control should get you where you need to go.

我认为WebBrowser 控件的DocumentCompleted事件应该让你到达你需要去的地方。

回答by AnthonyWJones

Assuming the "commit" element represents a standard Form submit button then you can attach an event handler to the WebBrowsers Navigated event.

假设“commit”元素代表一个标准的表单提交按钮,那么您可以将事件处理程序附加到 WebBrowsers Navigated 事件。

回答by PHeiberg

Have a go at Selenium (http://seleniumhq.org) or WatiN (http://watin.sourceforge.net) to save yourself some work.

试试 Selenium ( http://seleniumhq.org) 或 WatiN ( http://watin.sourceforge.net) 以节省一些工作。

回答by PHeiberg

This code was very helpful for me. Maybe it could be for you also

这段代码对我很有帮助。也许它也适合你

wb.Navigate(url);
while(wb.ReadyState != WebBrowserReadyState.Complete)
{
     Application.DoEvents();
}
MessageBox.Show("Loaded");

回答by Y?ld?zGezen

Best way to do this without blocking the UI thread is to use Async and Await introduced in .net 4.5.
You can paste this in your code just change the Browser to your webbrowser name. This way, your thread awaitsthe page to load, if it doesnt on time, it stops waiting and your code continues to run:

在不阻塞 UI 线程的情况下执行此操作的最佳方法是使用 .net 4.5 中引入的 Async 和 Await。
您可以将其粘贴到您的代码中,只需将浏览器更改为您的网络浏览器名称即可。这样,您的线程会等待页面加载,如果它没有按时加载,它将停止等待并且您的代码继续运行:

private async Task PageLoad(int TimeOut)
    {
        TaskCompletionSource<bool> PageLoaded = null;
        PageLoaded = new TaskCompletionSource<bool>();
        int TimeElapsed = 0;
        Browser.DocumentCompleted += (s, e) =>
        {
            if (Browser.ReadyState != WebBrowserReadyState.Complete) return;
            if (PageLoaded.Task.IsCompleted) return; PageLoaded.SetResult(true);
        };
        //
        while (PageLoaded.Task.Status != TaskStatus.RanToCompletion)
        {
            await Task.Delay(10);//interval of 10 ms worked good for me
            TimeElapsed++;
            if (TimeElapsed >= TimeOut * 100) PageLoaded.TrySetResult(true);
        }
    }

And you can use it like this, with in an async method, or in a button click event, just make it async:

您可以像这样使用它,在异步方法中,或在按钮单击事件中,只需使其异步:

private async void Button1_Click(object sender, EventArgs e)
{
   Browser.Navigate("www.example.com");
   await PageLoad(10);//await for page to load, timeout 10 seconds.
   //your code will run after the page loaded or timeout.
}

回答by Vlad K

Task method worked for me, except Browser.Task.IsCompleted has to be changed to PageLoaded.Task.IsCompleted.

任务方法对我有用,除了 Browser.Task.IsCompleted 必须更改为 PageLoaded.Task.IsCompleted。

Sorry I didnt add comment, that is because I need higher reputation to add comments.

抱歉我没有添加评论,那是因为我需要更高的声誉才能添加评论。

回答by bh_earth0

yuna and bnl code failed in the case below;

yuna 和 bnl 代码在以下情况下失败;

failing example:

失败的例子:

1st one waits for completed.but, 2nd one with the invokemember("submit") didnt . invoke works. but ReadyState.Complete acts like its Completed before its REALLY completed:

第一个等待完成。但是,第二个没有 invokemember("submit") 。调用作品。但是 ReadyState.Complete 在它真正完成之前就像它的 Completed 一样:

wb.Navigate(url);
while(wb.ReadyState != WebBrowserReadyState.Complete)
{
   Application.DoEvents();
}
MessageBox.Show("ok this waits Complete");

//navigates to new page
wb.Document.GetElementById("formId").InvokeMember("submit");
while(wb.ReadyState != WebBrowserReadyState.Complete)
{
   Application.DoEvents();
}
MessageBox.Show("webBrowser havent navigated  yet. it gave me previous page's html.");  
var html = wb.Document.GetElementsByTagName("HTML")[0].OuterHtml;


how to fix this unwanted situation:

如何解决这种不需要的情况:

usage

用法

    public myForm1 {

        myForm1_load() { }

        // func to make browser wait is inside the Extended class More tidy.
        WebBrowserEX wbEX = new WebBrowserEX();

        button1_click(){
            wbEX.Navigate("site1.com");
            wbEX.waitWebBrowserToComplete(wb);

            wbEX.Document.GetElementById("input1").SetAttribute("Value", "hello");
            //submit does navigation
            wbEX.Document.GetElementById("formid").InvokeMember("submit");
            wbEX.waitWebBrowserToComplete(wb);
            // this actually waits for document Compelete. worked for me.

            var processedHtml = wbEX.Document.GetElementsByTagName("HTML")[0].OuterHtml;
            var rawHtml = wbEX.DocumentText;
         }
     }

//put this  extended class in your code.
//(ie right below form class, or seperate cs file doesnt matter)
public class WebBrowserEX : WebBrowser
{
   //ctor
   WebBrowserEX()
   {
     //wired aumatically here. we dont need to worry our sweet brain.
     this.DocumentCompleted += (o, e) => { webbrowserDocumentCompleted = true;};
   }
     //instead of checking  readState, get state from DocumentCompleted Event 
     // via bool value
     bool webbrowserDocumentCompleted = false;
     public void waitWebBrowserToComplete()
     {
       while (!webbrowserDocumentCompleted )
       { Application.DoEvents();  }
       webbrowserDocumentCompleted = false;
     }

 }