2009-05-08 6 views
14

Vor Beginn diese Frage schreiben, versuche ich wurde nachWie WebBrowser Steuerelement DocumentCompleted Ereignis in C# verwenden?

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

das Problem zu lösen war, dass, wenn ein iframe auf einer Webseite vorhanden ist, würde Document Ereignis mehr als einmal gefeuert werden (nach jedem Dokument abgeschlossen ist). Es war sehr wahrscheinlich, dass das Programm versucht hätte, Daten aus dem DOM zu lesen, die nicht vollständig waren und natürlich fehlschlagen.

Aber plötzlich beim Schreiben dieser Frage ‚Was wäre, wenn‘ Monster mich inspiriert, und ich fix'ed das Problem, dass ich zu lösen versuchte. Da ich das bei Google nicht geschafft habe, dachte ich, es wäre nett, es hier zu posten.

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 
    } 

Für jetzt zumindest scheint mein 5m Hack gut zu funktionieren.

Vielleicht bin ich wirklich fehlgeschlagen bei der Abfrage von Google oder MSDN, aber ich kann nicht finden: "Wie verwendet man das webbrowser Steuerelement DocumentCompleted Ereignis in C#?"

Bemerkung: Nachdem ich viel über Webcontrol gelernt habe, habe ich festgestellt, dass es FuNKY Zeug macht.

Auch wenn Sie feststellen, dass das Dokument abgeschlossen ist, wird es in den meisten Fällen nicht für immer so bleiben. Die Seitenaktualisierung kann auf verschiedene Arten erfolgen: Frame-Refresh, Ajax-ähnliche Anfrage oder Server-Side-Push (Sie benötigen eine Kontrolle, die asynchrone Kommunikation unterstützt und über HTML- oder JavaScript-Interop verfügt). Außerdem werden einige Iframes niemals geladen, daher ist es nicht die beste Idee, für immer auf sie zu warten.

ich landete mit:

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

Was ist der Status der IsBusy-Eigenschaft während des DocumentCompleted-Ereignisses? – AMissico

+0

IsBusy wird false zurückgeben, sobald der erste Frame bereit ist. – Margus

+1

Nur eine Anmerkung, Ihr Code wird nicht mit mehreren normalen Frames arbeiten. –

Antwort

14

Sie möchten vielleicht auch die AJAX-Aufrufe wissen.

Betrachten Sie dies mit:

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, aber der else-Teil würde das REAL DOCUMENT COMPLETE enthalten, wo die IFRAME – pug

+0

@pug die if-Bedingung wäre, die ich bearbeitet habe, um das anzuzeigen. – AaronLS

0

ich etwas Ähnliches zu tun hatte. Was ich tue, ist ShDocVw direkt zu verwenden (Hinzufügen eines Verweises auf alle notwendigen Interop-Assemblys zu meinem Projekt). Dann füge ich das WebBrowser-Steuerelement meinem Formular nicht hinzu, aber das AXShDocVw.AxWebBrowser Steuerelement.

zu navigieren und warte ich auf folgende Methode verwenden:

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

Nur eine Anmerkung zu diesem, es wird fehlschlagen ist die Seite verwendet Ajax, da die Seite nie "Complete" wird. –

3

Ich habe noch Online eine funktionierende Lösung für dieses Problem zu finden. Hoffentlich schafft es das nach oben und spart jedem die Monate der Feinabstimmung, die ich damit verbracht habe, es zu lösen, und die Randfälle, die damit verbunden sind. Ich habe im Laufe der Jahre um dieses Problem gekämpft, da Microsoft die Implementierung/Zuverlässigkeit von isBusy und document.readystate geändert hat. Mit IE8 musste ich auf die folgende Lösung zurückgreifen. Es ist ähnlich der Frage/Antwort von Margus mit ein paar Ausnahmen. Mein Code behandelt verschachtelte Frames, Javascript/Ajax-Anfragen und Meta-Weiterleitungen. Ich habe den Code aus Gründen der Übersichtlichkeit vereinfacht, aber ich benutze auch eine Timeout-Funktion (nicht im Lieferumfang enthalten), um die Webseite zurückzusetzen, nachdem 5 Minuten domAccess immer noch gleich falsch ist.

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

Könntest du vielleicht die Unterschiede zu früheren IE Versionen erklären? – peterchen

+1

In meinen frühen Jahren der Webbrowser-Automatisierung konnte ich einfach die documentcomplete-Funktion nutzen - das war um 2002/3 - also 5,5/6. Wenn Ihr pdisp-Objekt mit dem obersten Dokumentfenster übereinstimmt, war das Dokument vollständig bereit und wurde immer ausgelöst. In diesen Tagen ~ wenn es zündet, können Sie sicher sein, dass Ihr Dokument bereit ist. Aber woher wissen Sie, wenn ein Ereignis in einem asynchronen Ereignismodell ohne ein großes ineffizientes Timeout nicht auftritt? IsBusy war ein guter Indikator für die Änderung des Mauszeigers, aber ich habe gesehen, IsBusy in der letzten Version von 7 & 8 unbegrenzt wahr bleiben. –

+0

Und wenn ich mich richtig erinnere AJAX-Anfragen nicht richtig ausgelöst dieses Ereignis bis IE6 und seit ie7 oder ie8 triggern sie jetzt vor dem Navigieren von Ereignissen doppelt. Und kümmern Sie sich nicht einmal darum, dass die Navigation abgeschlossen ist oder vollständige Ereignisse heruntergeladen werden, da sie Ihnen nicht helfen, den Beendigungsstatus eines Navigationslebenszyklus zu bestimmen. –

2

Im Gegensatz zu Thorsten ich nicht SHDocVw verwenden hatte, aber was den Unterschied machte mir die Schleife wurde das Hinzufügen Readystate prüft und mit Anwendung.DoEvents() während nicht bereit. Hier ist mein Code:

 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(); 
      } 
     } 

Und benutzte ich Yukis Lösung für die Ergebnisse der WebBrowser_DocumentCompleted Überprüfung, wenn auch mit dem letzten if/else pro Benutzer Kommentar vertauscht:

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

wie ein Charme :)

-1

Nur gedacht, hier ein paar Zeilen über eine kleine Verbesserung, die in Verbindung mit dem Code von FeiBao funktioniert. Die Idee besteht darin, eine Landmarkenvariable (Javascript) in die Webseite zu injizieren und diese zu verwenden, um zu erkennen, welches der nachfolgenden DocumentComplete-Ereignisse das wirkliche Geschäft ist. Ich bezweifle, dass es kugelsicher ist, aber es hat im Allgemeinen zuverlässiger funktioniert als der Ansatz, dem es fehlt. Alle Kommentare sind willkommen. Hier ist der Standardcode:

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