HTML - 我如何知道什么时候所有的框架都加载完毕?

问题描述 投票:12回答:12

我正在使用.NET WebBrowser控件,我如何知道一个网页何时被完全加载?

我想知道浏览器何时不再获取任何数据。(当IE在其状态栏中写下'Done'的时候...)。

注释:我想知道什么时候浏览器不再获取任何数据(IE在其状态栏中写下'Done'的时刻)。

  • 对于一个包含多个框架的网站,DocumentCompleteNavigateComplete事件可能会发生多次。
  • 浏览器准备状态也不能解决问题。
  • 我试过检查框架集合中的框架数量,然后计算得到DocumentComplete事件的次数,但这也不行。
  • this.WebBrowser.IsBusy也不行。当在Document Complete处理程序中检查它时,它总是'false'。
c# html browser mshtml
12个回答
3
投票

下面是我在应用中解决这个问题的方法。

private void wbPost_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url != wbPost.Url)
        return;
    /* Document now loaded */
}

2
投票

我的做法是 当页面完全加载时 包括框架)是这样的。

using System.Windows.Forms;
    protected delegate void Procedure();
    private void executeAfterLoadingComplete(Procedure doNext) {
        WebBrowserDocumentCompletedEventHandler handler = null;
        handler = delegate(object o, WebBrowserDocumentCompletedEventArgs e)
        {
            ie.DocumentCompleted -= handler;
            Timer timer = new Timer();
            EventHandler checker = delegate(object o1, EventArgs e1)
            {
                if (WebBrowserReadyState.Complete == ie.ReadyState)
                {
                    timer.Dispose();
                    doNext();
                }
            };
            timer.Tick += checker;
            timer.Interval = 200;
            timer.Start();
        };
        ie.DocumentCompleted += handler;
    }

从我的其他方法中,我学到了一些 "不要":

  • 不要试图弯曲勺子... ;-)
  • 不要试图使用DocumentComplete, Frames, HtmlWindow.Load事件来建立复杂的结构。如果你的解决方案能正常工作,那么它将是脆弱的。
  • 不要使用 System.Timers.Timer 而不是 Windows.Forms.Timer如果你这样做,奇怪的错误就会开始在奇怪的地方发生,因为定时器运行在不同的线程上,而不是你的应用程序的其余部分。
  • 不要只使用Timer而不使用DocumentComplete,因为它可能会在你的页面开始加载之前就启动,并且会过早地执行你的代码。

2
投票

这是我的测试版本。只要把它变成你的 DocumentCompleted Event Handler 并把你只想调用的代码放在这里。曾经 纳入该方法 OnWebpageReallyLoaded(). 实际上,这种方法是在页面稳定了200ms的时候,判断出页面已经稳定了,然后做它的事情。

// event handler for when a document (or frame) has completed its download
Timer m_pageHasntChangedTimer = null;
private void webBrowser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e ) {
    // dynamic pages will often be loaded in parts e.g. multiple frames
    // need to check the page has remained static for a while before safely saying it is 'loaded'
    // use a timer to do this

    // destroy the old timer if it exists
    if ( m_pageHasntChangedTimer != null ) {
        m_pageHasntChangedTimer.Dispose();
    }

    // create a new timer which calls the 'OnWebpageReallyLoaded' method after 200ms
    // if additional frame or content is downloads in the meantime, this timer will be destroyed
    // and the process repeated
    m_pageHasntChangedTimer = new Timer();
    EventHandler checker = delegate( object o1, EventArgs e1 ) {
        // only if the page has been stable for 200ms already
        // check the official browser state flag, (euphemistically called) 'Ready'
        // and call our 'OnWebpageReallyLoaded' method
        if ( WebBrowserReadyState.Complete == webBrowser.ReadyState ) {
            m_pageHasntChangedTimer.Dispose();
            OnWebpageReallyLoaded();
        }
    };
    m_pageHasntChangedTimer.Tick += checker;
    m_pageHasntChangedTimer.Interval = 200;
    m_pageHasntChangedTimer.Start();
}

OnWebpageReallyLoaded() {
    /* place your harvester code here */
}

0
投票

不如在每个框架中使用javascript在框架完成时设置一个标志,然后让C#查看这些标志?


0
投票

我不确定是否可行,但可以尝试在你的框架集上添加一个JavaScript "onload "事件,像这样 。

function everythingIsLoaded() { alert("everything is loaded"); }
var frameset = document.getElementById("idOfYourFrameset");
if (frameset.addEventListener)
    frameset.addEventListener('load',everythingIsLoaded,false); 
else
    frameset.attachEvent('onload',everythingIsLoaded); 

0
投票

你能用jQuery吗?这样你就可以很容易地在目标帧上绑定帧就绪事件。请看 这个 回答方向。这个 博文 也有关于它的讨论。最后还有一个 插件 你可以使用的。

这个想法是,你使用...来计算网页中的帧数,然后你计算iframe ready事件被触发的次数。

$("iframe").size()

然后计算iframe ready事件被触发的次数。


0
投票

你将得到一个BeforeNavigate和DocumentComplete事件,用于外部网页,以及每个框架。 当你得到外层网页的DocumentComplete事件时,你就知道你已经完成了。 你应该能够使用管理的等价的 IWebBrowser2::TopLevelContainer() 来确定这一点。

但是要注意,网站本身可以随时触发更多的框架导航,所以你永远不知道一个页面是否真的永远完成了。 你能做的最好的事情就是统计你看到的所有BeforeNavigates,并在得到DocumentComplete时减少计数。

编辑:这里是管理文档。TopLevelContainer.


0
投票

下面是我最终的工作原理。

       public bool WebPageLoaded
    {
        get
        {
            if (this.WebBrowser.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
                return false;

            if (this.HtmlDomDocument == null)
                return false;

            // iterate over all the Html elements. Find all frame elements and check their ready state
            foreach (IHTMLDOMNode node in this.HtmlDomDocument.all)
            {
                IHTMLFrameBase2 frame = node as IHTMLFrameBase2;
                if (frame != null)
                {
                    if (!frame.readyState.Equals("complete", StringComparison.OrdinalIgnoreCase))
                        return false;

                }
            }

            Debug.Print(this.Name + " - I think it's loaded");
            return true;
        }
    }

在每个文档完成事件中,我运行所有的html元素并检查所有可用的框架(我知道它可以被优化)。对于每一个框架,我检查它的准备状态.这是相当可靠的,但就像jeffamaphone说,我已经看到的网站,触发一些内部刷新。但是上面的代码可以满足我的需求。

编辑:每个框架都可以包含框架,所以我认为这段代码应该更新为递归检查每个框架的状态。


0
投票

我只是使用webBrowser.StatusText方法。当它说 "Done "时,所有的东西都被加载了!还是我遗漏了什么?


0
投票

检查IE.readyState = READYSTATE_COMPLETE应该可以,但如果这对你来说不可靠,而且你真的想知道 "当IE在其状态栏中写下'Done'的时刻",那么你可以做一个循环,直到IE.StatusText包含 "Done"。


0
投票

你有没有试过 WebBrowser.IsBusy 财产?


0
投票

我没有办法给你选择,但我想知道,如果? IsBusytrue 是因为该处理程序仍在运行,因此,在文档完成处理程序中的 WebBrowser 控制在技术上仍然是 "繁忙 "的。

最简单的解决方案是每隔100毫秒执行一次循环,直到该控件的 IsBusy 标志被重置(在错误的情况下有一个最大执行时间)。当然,前提是 IsBusy 将不会被设置为 false 在页面加载期间的任何时候。

如果文档完整处理程序在另一个线程上执行,您可以使用锁将您的主线程送入睡眠状态,然后从文档完整线程中唤醒它。然后检查 IsBusy 标志,重新锁定主线是其仍然是其 true.

© www.soinside.com 2019 - 2024. All rights reserved.