2009-03-23 8 views
11

Utilizzo il controllo WebBrowser .NET. Come faccio a sapere quando una pagina web è completamente caricata?HTML: come faccio a sapere quando vengono caricati tutti i frame?

Voglio sapere quando il browser non sta recuperando altri dati. (Il momento in cui IE scrive "Fatto" nella sua barra di stato ...).

Note:

  • Gli eventi DocumentComplete/NavigateComplete potrebbero verificarsi più volte per un sito web che contiene più frame.
  • Lo stato di pronto per il browser non risolve il problema.
  • Ho provato a verificare il numero di frame nella raccolta fotogrammi e quindi a contare il numero di volte in cui ottengo l'evento DocumentComplete ma questo non funziona neanche.
  • this.WebBrowser.IsBusy non funziona neanche. È sempre 'falso' quando lo si controlla nel gestore completo del documento.

risposta

1

Ecco ciò che alla fine ha funzionato per me:

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

Su ogni documento evento complete corro su tutto l'elemento html e controllare tutti i fotogrammi disponibili (so che può essere ottimizzato). Per ogni frame ne controllo lo stato di pronto. È abbastanza affidabile ma proprio come jeffamaphone ha detto che ho già visto siti che hanno attivato alcuni aggiornamenti interni. Ma il codice sopra soddisfa le mie esigenze.

Modifica: ogni fotogramma può contenere fotogrammi al suo interno quindi penso che questo codice debba essere aggiornato per verificare ricorsivamente lo stato di ogni fotogramma.

0

Hai provato WebBrowser.IsBusy proprietà?

+1

sì. Il browser Web dichiara di non essere occupato ogni volta che viene chiamato il gestore completo del documento ... –

0

Che ne dici di usare javascript in ogni frame per impostare un flag quando il frame è completo, e quindi C# guarda le flag?

+0

Non voglio modificare l'albero DOM di ogni sito a cui il browser sta navigando. Ma supponiamo che io usi la tua soluzione, come faccio in javascript? –

+0

Non vedo il vantaggio di farlo in JS vs C#. –

0

Non ho un'alternativa per voi, ma mi chiedo se la proprietà IsBusy essendo tru e durante il Documento gestore Complete è perché il gestore è ancora in esecuzione e quindi il controllo WebBrowser è tecnicamente ancora 'occupato'.

La soluzione più semplice sarebbe avere un ciclo che viene eseguito ogni 100 ms circa fino a quando il flag viene reimpostato (con un tempo di esecuzione massimo in caso di errori). Ciò ovviamente presuppone che IsBusy non sia impostato su false in qualsiasi momento durante il caricamento della pagina.

Se il gestore completo del documento viene eseguito su un altro thread, è possibile utilizzare un blocco per inviare il thread principale in stato di stop e riattivarlo dal thread Document Complete. Quindi controllare il flag , il nuovo blocco del thread principale è ancora true.

+0

Ma IsBusy è impostato su false troppo presto. Ad esempio, se hai sei frame in una pagina web, quando il primo frame completa il caricamento, l'IsBusy è falso sull'evento DocumentComplete. –

+0

Ogni frame riceve il proprio browser (implementazione IWebBrowser2). Probabilmente l'attributo IsBusy si applica solo al frame specifico. E quando è completo, non è più occupato. –

0

Io non sono sicuro che funzionerà, ma tenta di aggiungere un evento JavaScript "onload" sul set di cornici come quella:

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

Voglio essere in grado di sapere se tutti i frame sono caricati per qualsiasi sito web, quindi non so quali frame contiene. –

+0

Dovresti farlo sul set di frame (padre di tutti i frame), non su ogni frame. È abbastanza facile ottenerlo da qualsiasi sito web del genere: document.getElementsByTagName ('frameset') [0] – paulgreg

0

È possibile utilizzare jQuery? Quindi potresti facilmente associare eventi pronti per il frame sui frame di destinazione. Vedi la risposta this per le indicazioni. Questo blog post ha anche una discussione a riguardo. Infine c'è un plug-in che potresti usare.

L'idea è che si conta il numero di fotogrammi nella pagina web utilizzando:

$("iframe").size() 

e poi si conta quante volte l'iframe pronto evento è stato licenziato.

0

Si otterrà un evento BeforeNavigate e DocumentComplete per la pagina Web esterna, nonché ciascun frame. Sai che hai finito quando ottieni l'evento DocumentComplete per la pagina web esterna. Dovresti essere in grado di utilizzare l'equivillo gestito di IWebBrowser2::TopLevelContainer() per determinare ciò.

Attenzione, tuttavia, il sito Web stesso può attivare più navigazioni di frame ogni volta che lo desidera, in modo da non sapere mai se una pagina è veramente fatta per sempre. Il meglio che puoi fare è tenere un conteggio di tutti i BeforeNavigates che vedi e decrementare il conteggio quando ottieni un DocumentComplete.

Modifica: ecco i documenti gestiti: TopLevelContainer.

+1

Ho provato a contare il precedente e il documento completo nel controllo WebBrowser. Non è sincronizzato ... :(. Ci sono molti altri elementi prima della navigazione che il documento completo. [Forse ha a che fare con la memorizzazione nella cache o con i frame duplicati che sono stati recuperati.] –

+0

Per quanto riguarda l'evento completo del documento: in C# WebBrowser non ottieni l'oggetto documento che ha appena completato il caricamento. Solo l'url, quindi non puoi accedere al suo contenitore del browser. –

2

Il mio approccio a fare qualcosa quando la pagina viene caricata completamente (compresi frame) è qualcosa di simile:

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

Dalle mie altri approcci ho imparato un po 'di "non" -s:

  • non provare a piegare il cucchiaio ... ;-)
  • non provare a costruire costrutto elaborato utilizzando gli eventi DocumentComplete, Frames, HtmlWindow.Load. La tua soluzione sarà fragile se lavori affatto.
  • non utilizzare System.Timers.Timer anziché Windows.Forms.Timer, si verificano strani errori che si verificano in luoghi strani se lo si fa, a causa del timer in esecuzione su thread diversi rispetto al resto della propria app.
  • non utilizzare solo il timer senza DocumentComplete perché potrebbe attivarsi prima che la pagina inizi a caricarsi e eseguirà il codice prematuramente.
2

Ecco come ho risolto il problema nella mia domanda:

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

Se ad esempio fai un clic su una barra di navigazione e fa sì che un nuovo sito web venga ricaricato in una cornice/iframe, non sarai felice con questa soluzione –

0

mi basta usare il metodo webBrowser.StatusText. Quando dice "Fatto" tutto è caricato! O mi manca qualcosa?

+0

Negativo se c'è iframe –

2

Ecco la mia versione testata. Basta fare questo il tuo DocumentCompleted Event Handler e inserire il codice che si desidera essere chiamato una volta nel metodo OnWebpageReallyLoaded(). In effetti, questo approccio determina quando la pagina è rimasta stabile per 200ms e poi fa la sua parte.

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

Mille grazie! Funziona perfettamente per me. – selegnasol

0

Controllo per IE.readyState = READYSTATE_COMPLETE dovrebbe funzionare, ma non se questo è dimostrando affidabile per voi e vi letteralmente vogliono sapere "il momento in cui IE scrive 'Fatto' nella sua barra di stato", allora si può fare un ciclo fino a IE.StatusText contiene "Fatto".

Problemi correlati