检测Web浏览器完整页面加载

63

如何检测System.Windows.Forms.WebBrowser控件何时加载完成?

我尝试使用Navigate和DocumentCompleted事件,但它们在文档加载期间都会被多次引发!


你是如何使用C#的?这是一个ASP.NET问题,还是你正在使用Web浏览器控件? - kibibu
@kibibu 我正在使用WebBrowser控件。 - Neir0
如果页面有很多框架,比较AbsolutePath可能不起作用。我以前尝试过那种方法,但还没有成功。我仍然被这个问题困扰。:( :( - user521984
9个回答

37

我认为DocumentCompleted事件也会触发所有子文档的加载(例如JS和CSS)。您可以查看DocumentCompleted中的WebBrowserDocumentCompletedEventArgs,并检查Url属性,将其与主页面的Url进行比较。


这是我从自己解决这个问题中得出的结论。我发现在像广告横幅之类的东西上会得到许多额外的完成。我丢弃任何与我想要的URL不匹配的事件,这样就可以解决问题了。 - Loren Pechtel
6
@Loren Pechtel 很抱歉要说这种方法存在三个问题。首先,当您的父(最高级别)URL执行服务器端URL重定向时,您要比较的文档的URL会更改。其次,在一个框架和父页面具有相同URL的情况下,根据其他参数(如引用者等),它们的行为会发生变化,因此URL是相同的。此外,客户端重定向-它们发生在您认为页面已加载完成并且web浏览器控件返回“一切都好”的状态之后。如果您想要了解如何减少这些问题,请让我知道,我可以在这里提供答案。 - Erx_VB.NExT.Coder
@Paul Kearney - PK,随意阅读我最后一条评论给Loren。 - Erx_VB.NExT.Coder
凭直觉猜测,我打赌脚本不会触发documentloaded事件,因为它们没有附加DOMDocument。这很可能是因为有框架存在,因为包含框架集的HTML片段在技术上嵌入了窗口,从而形成多个文档。 - mschr

31

我做了以下操作:

void BrowserDocumentCompleted(object sender,
        WebBrowserDocumentCompletedEventArgs e)
{
  if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath)
    return; 

  //The page is finished loading 
}

通常最后加载的页面是被导航到的页面,所以这应该可以解决问题。

来自这里


完美 - 正是我所需要的。解释了为什么有时整个页面出现,有时只有部分页面。 - Elie
只需将其更改为 ((WebBrowser)sender).Url ;-) - juFo
1
不太好使。 问题在于有Facebook和Twitter的内容,主要问题是如果页面通过ajax使用js加载内容。所有内容都在documentReady事件中。 - Péter
如何调用它?我尝试调用BrowserDocumentCompleted(sender, e); - Ave
@vanloc 名称并不重要。您只需要将其分配给WebBrowser控件的DocumentCompleted事件即可。 - Tom Lint

19
以下代码应该可以正常工作。
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    //Check if page is fully loaded or not
    if (this.webBrowser1.ReadyState != WebBrowserReadyState.Complete)
        return;
    else
        //Action to be taken on page loading completion
}

非常有帮助且简单! - Joe DF
1
在我的应用程序中,该事件至少被触发四次。 - Jack Griffin
@JackGriffin 这是因为每个 iframe 也是一个文档,因此会触发事件。这很棘手。你可以像 Paul 在上面的答案中提到的那样检查 Urls,但这也可能失败,就像 Erx_VB.NExT.Coder 所描述的那样。如果要打开的 URL 属于某个预定义的 URL 集合,则您可能知道如何避免这些问题。例如,当我第一次遇到这个问题时,我知道将要打开哪些 URL,所以我创建了 WebBrowser 类的子类并添加了一些附加信息。然后,通过提示发送方对象,这很容易做到。 - Transcendental
@Transcendental 我看到了问题。Kyle的解决方案对我有效,但也许我只是幸运:-)。 - Jack Griffin
我也是。我的应用程序每两次就会触发一次。 - JHK

13
注意,由于服务器转移或URL规范化(例如,您导航到www.microsoft.com并在documentcomplete中得到http://www.microsoft.com),DocumentCompleted中的URL可能与导航URL不同。
在没有框架的页面中,此事件在加载完成后仅触发一次。在具有多个框架的页面中,此事件为每个导航帧触发一次(请注意,在帧内支持导航,例如单击帧中的链接可以将帧导航到另一页)。最高级别的导航框架(可能是顶级浏览器,也可能不是)会触发最终的DocumentComplete事件。
在本机代码中,您将比较DocumentComplete事件的发送者以确定该事件是否是导航中的最终事件。但是,在Windows Forms中,sender参数未被WebBrowserDocumentCompletedEventArgs包装。您可以接收本机事件以获取参数值,或者检查DocumentCompleted事件处理程序中的浏览器的readystate属性框架文档,以查看所有框架是否处于就绪状态。

如果存在下载管理器并且导航到可下载文件时,readystate方法存在问题,导航可能会被下载管理器取消,从而使读取状态无法变为完成。


6
我曾经遇到过多次触发DocumentCompleted事件的问题,尝试了以上所有建议。最终,在我的情况下,既不是IsBusy属性正常工作,也不是Url属性,而是ReadyState似乎是我需要的,因为在加载多个框架时它具有“交互”状态,并且只有在加载最后一个框架后才获得“完成”状态。因此,我知道页面已经完全加载了所有组件。

希望这也能帮助其他人 :)


3

似乎对于外部JavaScript或CSS文件不会触发DocumentCompleted / Navigated事件,但对于iframe则会触发。根据PK的说法,比较WebBrowserDocumentCompletedEventArgs.Url属性(我还没有评论的权限)。


3
如果您正在使用WPF,则有一个LoadCompleted事件。
如果是Windows.Forms,则DocumentCompleted事件应该是正确的。如果您加载的页面具有框架,则您的WebBrowser控件将为每个框架触发DocumentCompleted事件(有关更多详细信息,请参见此处)。建议每次事件被触发时检查IsBusy属性,如果为false,则您的页面已完全加载完成。

0

您可以使用 ProgressChanged 事件;它最后一次被引发时将指示文档已完全呈现:

this.webBrowser.ProgressChanged += new
WebBrowserProgressChangedEventHandler(webBrowser_ProgressChanged);

12
你怎么知道这是最后一次通话? - tmorell

0

使用DocumentCompleted事件处理带有多个嵌套框架的页面对我无效。

我使用Interop.SHDocVW库将WebBrowser控件进行了转换,如下所示:

public class webControlWrapper
{
    private bool _complete;
    private WebBrowser _webBrowserControl;

    public webControlWrapper(WebBrowser webBrowserControl)
    {
        _webBrowserControl = webBrowserControl;
    }

    public void NavigateAndWaitForComplete(string url)
    {
        _complete = false;

        _webBrowserControl.Navigate(url);

        var webBrowser = (SHDocVw.WebBrowser) _webBrowserControl.ActiveXInstance;

        if (webBrowser != null)
            webBrowser.DocumentComplete += WebControl_DocumentComplete;

        //Wait until page is complete
        while (!_complete)
        {
            Application.DoEvents();
        }
    }

    private void WebControl_DocumentComplete(object pDisp, ref object URL)
    {
        // Test if it's the main frame who called the event.
        if (pDisp == _webBrowserControl.ActiveXInstance)
            _complete = true;
    }

这段代码在使用webBrowserControl.Navigate(url)方法导航到指定URL时对我有效,但是当使用htmlElement.InvokeMember("click")点击HTML按钮时,我不知道如何控制页面完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接