2009-05-08 19 views
14

この質問を書き始める前に、私は、IFRAMEがWebページ上に存在する場合は、各文書が完了した後、DocumentCompletedイベントが(その後、もう一度解雇になるだろうという、問題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 

次解決するためにしてしようとしていました)。プログラムが完了していないDOMからデータを読み取ろうとしていて、自然に失敗した可能性が高いです。

しかし、この質問を書いて、突然ながらモンスター「場合何が私にインスピレーションを得た、と私は私が解決しようとしたことが、問題をfix'ed。 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 
    } 

今のところ、少なくとも5mのハックが正常に機能しているようです。

GoogleまたはMSDNのクエリに実際に失敗していますが、見つけられません。 「C#でWebcrowser Control DocumentCompletedイベントを使用する方法は?」

備考: Webcontrolについて多くのことを学んだ後、私はFuNKYのことを見つけました。

ドキュメントが完了したことを検出したとしても、ほとんどの場合、それは永遠に残ることはありません。ページの更新は、フレームリフレッシュ、ajaxのようなリクエストまたはサーバーサイドのプッシュ(非同期通信をサポートするいくつかのコントロールが必要で、htmlまたはJavaScript interopを持つ)などのいくつかの方法で行うことができます。また、一部のiframeはロードされませんので、永遠にそれらを待つのは最善の方法ではありません。

私が使用して終了:

if (e.Url != wb.Url) 
+0

DocumentCompletedイベントでのIsBusyプロパティの状態は? – AMissico

+0

IsBusyは、最初のフレームが準備完了次第、falseを返します。 – Margus

+1

あなたのコードは複数の通常のフレームでは機能しません。 –

答えて

14

また、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 
    } 
} 
+2

+1ですが、else部分にはREAL DOCUMENT COMPLETEが含まれています。if条件はIFRAME – pug

+0

@pugになります。これを示すために投稿を編集しました。 – AaronLS

0

私は似た何かをしなければなりませんでした。私が行うことは、ShDocVwを直接使用することです(プロジェクトに必要なすべてのinteropアセンブリへの参照を追加する)。その後、フォームに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(); 
} 
+2

ちょうどこれに注意してください、それはページが決して "完全"にならないので、ページがAjaxを使用していると失敗します。 –

3

私は、オンラインでこの問題に対する実用的なソリューションを見つけるためには至っていません。うまくいけば、これはトップになり、それを解決しようと努力した調整の数ヶ月、そしてそれに関連するエッジケースを皆に救うでしょう。 MicrosoftがisBusyとdocument.readystateの実装/信頼性を変更したので、私はこの問題を長年にわたって克服してきました。 IE8では、以下の解決策に頼らざるを得ませんでした。いくつかの例外を除いてMargusの質問/回答に似ています。私のコードは、ネストされたフレーム、javascript/ajaxリクエスト、メタリダイレクトを処理します。わかりやすくするためにコードを簡略化しましたが、5分のdomAccessがまだfalseに等しい場合は、タイムアウト機能(含まれていない)を使用してWebページをリセットします。

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; 
    } 
} 
+0

これまでのIEのバージョンとの違いを詳しく説明できますか? – peterchen

+1

ウェブブラウザーの初期の私は、documentcomplete関数を使用することができました。これは2002/3年頃です。つまり、ie5.5/6です。あなたのpdispオブジェクトが一番上のドキュメントウィンドウにマッチした場合、ドキュメントは完全に準備できていて、いつも起動していました。今日は、ドキュメントが準備されていることを保証することができますが、非効率的なタイムアウトを行わずに非同期イベントモデルでイベントが発生しないことをどのように知ることができますか? IsBusyはマウスカーソルを変更するための良い指標となりましたが、最近のバージョンの7&8ではIsBusyが無期限にとどまることがわかりました。 –

+0

そして、正しくリコールすれば、AJAXリクエストはIE6まで、 ie7またはie8は、イベントをナビゲートする前に重複をトリガーするようになりました。ナビゲーションライフサイクルの完了ステータスの決定に役立たないため、完全なイベントのナビゲートや完全なイベントのダウンロードは気にしないでください。 –

2

はトルステンと違って、私はSHDOCVWを使用する必要はありませんでしたが、私はreadyStateのをチェックするループを追加し、アプリケーションを使用していたために違いを生むやったこと:

これを使用することを検討してください。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(); 
      } 
     } 

および/他のユーザーのコメントごとに交換された場合、私は最後にかかわらず、WebBrowser_DocumentCompletedの結果をチェックするためユキのソリューションを使用:

 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 
     } 
    } 

が魅力のように働いた:)

-1

FeiBaoのコードと連携して動作する小さな改善点について、ここで1行または2行を削除すると考えました。このアイデアは、ランドマーク(javascript)変数をWebページに挿入し、それを使用して後続の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 
     } 
    } 
関連する問題