如何在C#中使用WebBrowser控件DocumentCompleted事件?

在开始写这个问题之前,我试图解决以下问题

// 1. navigate to page // 2. wait until page is downloaded // 3. read and write some data from/to iframe // 4. submit (post) form 

问题是,如果一个网页上存在一个iframe,DocumentCompleted事件会被触发多次(在每个文档完成之后)。 程序很可能试图从DOM中读取未完成的数据,并自然地失败。

但突然间,当写这个问题“假如”怪物激励我,我解决了这个问题,我试图解决。 因为我没有Google,所以我觉得在这里发布会很好。

  private int iframe_counter = 1; // needs to be 1, to pass DCF test public bool isLazyMan = default(bool); /// <summary> /// LOCK to stop inspecting DOM before DCF /// </summary> public void waitPolice() { while (isLazyMan) Application.DoEvents(); } private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) { if(!e.TargetFrameName.Equals("")) iframe_counter --; isLazyMan = true; } private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (!((WebBrowser)sender).Document.Url.Equals(e.Url)) iframe_counter++; if (((WebBrowser)sender).Document.Window.Frames.Count <= iframe_counter) {//DCF test DocumentCompletedFully((WebBrowser)sender,e); isLazyMan = false; } } private void DocumentCompletedFully(WebBrowser sender, WebBrowserDocumentCompletedEventArgs e){ //code here } 

至less现在,我5米的黑客似乎工作正常。

也许我真的在查询谷歌或MSDN失败,但我找不到:“如何在C#中使用webbrowser控件DocumentCompleted事件?

备注:在了解了很多关于网页控制的知识之后,我发现它确实是FuNKY的东西。

即使你发现文件已经完成,在大多数情况下,它不会永远保持这样的状态。 页面更新可以通过几种方式完成 – 帧刷新,像请求一样的ajax或服务器端的推送(你需要有一些支持asynchronous通信的控件,并且有html或者JavaScript interop)。 此外,一些iframe将永远不会加载,所以永远不要等待它们。

我结束了使用:

 if (e.Url != wb.Url) 

您也可能想知道AJAX调用。

考虑使用这个:

 private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { string url = e.Url.ToString(); if (!(url.StartsWith("http://") || url.StartsWith("https://"))) { // in AJAX } if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath) { // IFRAME } else { // REAL DOCUMENT COMPLETE } } 

我还没有find一个在线解决这个问题的工作。 希望这将使它到顶部,并保存每个人的调整我花了几个月的努力来解决它,以及与之相关的边缘案例。 多年来,我一直在争论这个问题,因为微软已经改变了isBusy和document.readystate的实现/可靠性。 IE8,我不得不诉诸以下解决scheme。 这与Margus的问题/答案类似,只有一些例外。 我的代码将处理嵌套的帧,javascript / ajax请求和元redirect。 为了清楚起见,我简化了代码,但是如果5分钟domAccess仍然等于false,我还使用超时function(不包括)来重置网页。

 private void m_WebBrowser_BeforeNavigate(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) { //Javascript Events Trigger a Before Navigate Twice, but the first event //will contain javascript: in the URL so we can ignore it. if (!URL.ToString().ToUpper().StartsWith("JAVASCRIPT:")) { //indicate the dom is not available this.domAccess = false; this.activeRequests.Add(URL); } } private void m_WebBrowser_DocumentComplete(object pDisp, ref object URL) { this.activeRequests.RemoveAt(0); //if pDisp Matches the main activex instance then we are done. if (pDisp.Equals((SHDocVw.WebBrowser)m_WebBrowser.ActiveXInstance)) { //Top Window has finished rendering //Since it will always render last, clear the active requests. //This solves Meta Redirects causing out of sync request counts this.activeRequests.Clear(); } else if (m_WebBrowser.Document != null) { //Some iframe completed dom render } //Record the final complete URL for reference if (this.activeRequests.Count == 0) { //Finished downloading page - dom access ready this.domAccess = true; } } 

与Thorsten不同的是,我不需要使用ShDocVw,但是对于我来说,添加循环检查ReadyState并使用Application.DoEvents()还没有做好准备。 这是我的代码:

  this.webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted); foreach (var item in this.urlList) // This is a Dictionary<string, string> { this.webBrowser.Navigate(item.Value); while (this.webBrowser1.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); } } 

我用Yuki的解决scheme来检查WebBrowser_DocumentCompleted的结果,尽pipe每个用户的评论最后一个if / else交换:

  private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { string url = e.Url.ToString(); var browser = (WebBrowser)sender; if (!(url.StartsWith("http://") || url.StartsWith("https://"))) { // in AJAX } if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath) { // IFRAME } else { // REAL DOCUMENT COMPLETE // Put my code here } } 

工作就像一个魅力:)

我不得不做类似的事情。 我所做的就是直接使用ShDocVw(将所有必要的互操作程序集的引用添加到我的项目中)。 然后,我不添加WebBrowser控件到我的窗体,但AXShDocVw.AxWebBrowser控件。

导航和等待我使用以下方法:

 private void GotoUrlAndWait(AxWebBrowser wb, string url) { object dummy = null; wb.Navigate(url, ref dummy, ref dummy, ref dummy, ref dummy); // Wait for the control the be initialized and ready. while (wb.ReadyState != SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE) Application.DoEvents(); } 

只是想在这里放一两行关于与飞宝代码结合的小改进。 这个想法是在网页中注入一个里程碑(javascript)variables,并用它来检测后面的DocumentComplete事件是真正的交易。 我怀疑这是不是防弹的,但它比一般的方法更可靠。 欢迎任何意见。 这是样板代码:

  void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { string url = e.Url.ToString(); var browser = (WebBrowser)sender; if (!(url.StartsWith("http://") || url.StartsWith("https://"))) { // in AJAX } if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath) { // IFRAME } else if (browser.Document != null && (bool)browser.Document.InvokeScript("eval", new object[] { @"typeof window.YourLandMarkJavascriptVariableHere === 'undefined'" })) { ((IHTMLWindow2)browser.Document.Window.DomWindow).execScript("var window.YourLandMarkJavascriptVariableHere = true;"); // REAL DOCUMENT COMPLETE // Put my code here } }