我正在使用.NET WebBrowser控件,我如何知道一个网页何时被完全加载?
我想知道浏览器何时不再获取任何数据。(当IE在其状态栏中写下'Done'的时候...)。
注释:我想知道什么时候浏览器不再获取任何数据(IE在其状态栏中写下'Done'的时刻)。
下面是我在应用中解决这个问题的方法。
private void wbPost_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url != wbPost.Url)
return;
/* Document now loaded */
}
我的做法是 当页面完全加载时 包括框架)是这样的。
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;
}
从我的其他方法中,我学到了一些 "不要":
System.Timers.Timer
而不是 Windows.Forms.Timer
如果你这样做,奇怪的错误就会开始在奇怪的地方发生,因为定时器运行在不同的线程上,而不是你的应用程序的其余部分。这是我的测试版本。只要把它变成你的 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 */
}
不如在每个框架中使用javascript在框架完成时设置一个标志,然后让C#查看这些标志?
我不确定是否可行,但可以尝试在你的框架集上添加一个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);
你将得到一个BeforeNavigate和DocumentComplete事件,用于外部网页,以及每个框架。 当你得到外层网页的DocumentComplete事件时,你就知道你已经完成了。 你应该能够使用管理的等价的 IWebBrowser2::TopLevelContainer() 来确定这一点。
但是要注意,网站本身可以随时触发更多的框架导航,所以你永远不知道一个页面是否真的永远完成了。 你能做的最好的事情就是统计你看到的所有BeforeNavigates,并在得到DocumentComplete时减少计数。
编辑:这里是管理文档。TopLevelContainer.
下面是我最终的工作原理。
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说,我已经看到的网站,触发一些内部刷新。但是上面的代码可以满足我的需求。
编辑:每个框架都可以包含框架,所以我认为这段代码应该更新为递归检查每个框架的状态。
我只是使用webBrowser.StatusText方法。当它说 "Done "时,所有的东西都被加载了!还是我遗漏了什么?
检查IE.readyState = READYSTATE_COMPLETE应该可以,但如果这对你来说不可靠,而且你真的想知道 "当IE在其状态栏中写下'Done'的时刻",那么你可以做一个循环,直到IE.StatusText包含 "Done"。
你有没有试过 WebBrowser.IsBusy
财产?
我没有办法给你选择,但我想知道,如果? IsBusy
被 true
是因为该处理程序仍在运行,因此,在文档完成处理程序中的 WebBrowser
控制在技术上仍然是 "繁忙 "的。
最简单的解决方案是每隔100毫秒执行一次循环,直到该控件的 IsBusy
标志被重置(在错误的情况下有一个最大执行时间)。当然,前提是 IsBusy
将不会被设置为 false
在页面加载期间的任何时候。
如果文档完整处理程序在另一个线程上执行,您可以使用锁将您的主线程送入睡眠状态,然后从文档完整线程中唤醒它。然后检查 IsBusy
标志,重新锁定主线是其仍然是其 true
.