2009-03-23 17 views
11

Estoy usando el control .NET WebBrowser. ¿Cómo puedo saber cuándo una página web está completamente cargada?HTML - ¿Cómo sé cuándo se cargan todos los marcos?

Quiero saber cuando el navegador no está obteniendo más datos. (El momento en que IE escribe 'Hecho' en su barra de estado ...).

Notas:

  • Los eventos Documento Completo/NavigateComplete podrían ocurrir varias veces para un sitio web que contiene varios fotogramas.
  • El estado de navegador preparado tampoco resuelve el problema.
  • He intentado verificar el número de fotogramas en la colección de marcos y luego contar la cantidad de veces que recibo el evento DocumentComplete, pero esto tampoco funciona.
  • this.WebBrowser.IsBusy tampoco funciona. Siempre es 'falso' al verificarlo en el controlador de Document Complete.

Respuesta

1

Esto es lo que finalmente funcionó para mí:

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

En cada documento evento completo corro sobre todo el elemento html y comprobar todos los marcos disponibles (ya sé que puede ser optimizado). Para cada cuadro verifico su estado de listo. Es bastante confiable, pero al igual que jeffamaphone, dijo que ya he visto sitios que desencadenaron algunas actualizaciones internas. Pero el código anterior satisface mis necesidades.

Editar: cada fotograma puede contener fotogramas, por lo que creo que este código debe actualizarse para comprobar recursivamente el estado de cada fotograma.

0

¿Has probado WebBrowser.IsBusy propiedad?

+1

yep. El navegador web dice que no debe estar ocupado cada vez que se llama al manejador de documento completo ... –

0

¿Qué le parece usar javascript en cada fotograma para establecer una bandera cuando el fotograma está completo y luego tener C# en las banderas?

+0

No quiero manipular el árbol DOM de cada sitio que navega el navegador. Pero supongamos que utilizo su solución, ¿cómo lo hago en javascript? –

+0

No veo la ventaja de hacer esto en JS vs C#. –

0

que no tienen una alternativa para usted, pero me pregunto si la propiedad IsBusy siendo tru e durante el alimentador de documentos completo se debe a que el controlador sigue en funcionamiento y por lo tanto el control WebBrowser técnicamente tienen 'ocupado'.

La solución más simple sería tener un bucle que se ejecute cada 100 ms aproximadamente hasta que se restablezca el indicador IsBusy (con un tiempo máximo de ejecución en caso de errores). Por supuesto, eso supone que IsBusy no se configurará en false en ningún momento durante la carga de la página.

Si el controlador de Document Complete se ejecuta en otro hilo, puede usar un candado para enviar su hilo principal a dormir y activarlo desde el hilo Document Complete. A continuación, compruebe la bandera IsBusy, volviendo a bloquear el hilo principal sigue siendo true.

+0

Pero el IsBusy está configurado como falso demasiado pronto. Por ejemplo, si tiene seis fotogramas en una página web, cuando el primer fotograma completa la carga, el IsBusy es falso en el evento DocumentComplete. –

+0

Cada marco obtiene su propio navegador web (implementación de IWebBrowser2). Es probable que el atributo IsBusy solo se aplique al marco específico. Y cuando está completo, ya no está ocupado. –

0

No estoy seguro de que va a trabajar, pero trate de añadir un evento de JavaScript "onload" en su conjunto de marcos de esa manera:

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

Quiero ser capaz de saber si todas las tramas son cargados para cualquier sitio web, así que no sé qué marcos que contiene. –

+0

Deberías hacer eso en el conjunto de marcos (principal de todos los fotogramas), no en cada fotograma. Es bastante fácil llegar a él desde cualquier sitio web de esa manera: document.getElementsByTagName ('marcos') [0] – paulgreg

0

Se puede usar jQuery? Luego, podría vincular fácilmente los eventos listos para el fotograma en los marcos objetivo. Consulte this para obtener instrucciones. Este blog post también tiene una discusión al respecto. Finalmente hay un plug-in que puede usar.

La idea es que se cuenta el número de cuadros en la página web usando:

$("iframe").size() 

y luego se cuenta cuántas veces el evento iframe lista se ha disparado.

0

Obtendrá un evento BeforeNavigate y DocumentComplete para la página web externa, así como también para cada fotograma. Ya sabes que terminaste cuando recibas el evento DocumentComplete para la página web externa. Debería poder usar el equiviente administrado de IWebBrowser2::TopLevelContainer() para determinar esto.

Tenga en cuenta, sin embargo, que el sitio web en sí puede desencadenar más navegaciones de marcos en cualquier momento que lo desee, por lo que nunca se sabe si una página se hace realmente para siempre. Lo mejor que puede hacer es llevar un recuento de todos los BeforeNavigates que ve y disminuir el conteo cuando obtiene un DocumentComplete.

Editar: Aquí están los documentos gestionados: TopLevelContainer.

+1

que intentó contar el antes y navega el documento completo en el control WebBrowser. .. No se sincroniza ... :(Hay más antes de navegar que documento completo [. Tal vez tiene que ver con el caché o duplicar los marcos que se recuperan no sé] –

+0

En cuanto al documento completo de eventos:. En C# WebBrowser no obtiene el objeto de documento que se acaba de completar la carga. Sólo la url. Así que no se puede llegar a su contenedor navegador. –

2

Mi acercamiento a hacer algo cuando la página se carga por completo (incluyendo marcos) es algo como esto:

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

De mis otros enfoques que aprendí un poco de "No" -s:

  • no tratan de doblar la cuchara ... ;-)
  • no tratan de construir constructo elaborado utilizando Documento Completo, Marcos, eventos HtmlWindow.Load. Su solución será frágil si trabaja en absoluto.
  • no use System.Timers.Timer en lugar de Windows.Forms.Timer, si lo hace, se producirán errores extraños en lugares extraños, debido a que el temporizador se ejecuta en una secuencia diferente que el resto de su aplicación.
  • no use solo el temporizador sin DocumentComplete porque puede disparar antes de que su página incluso comience a cargarse y ejecutará su código prematuramente.
2

Así es como he resuelto el problema en mi solicitud:

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

Si lo hace, por ejemplo, un clic en una barra de navegación y hace que un nuevo sitio web se vuelve a cargar en un marco/iframe, que no estarán contentos con esta solución. –

0

sólo tiene que utilizar el método webBrowser.StatusText. Cuando dice "Hecho", ¡todo está cargado! ¿O me estoy perdiendo algo?

+0

negativo si hay iframe –

2

Aquí está mi versión probada. Simplemente haga que este sea su DocumentCompleted Event Handler y coloque el código que solo quiere que se llame una vez en el método OnWebpageReallyLoaded(). Efectivamente, este enfoque determina cuándo la página se ha mantenido estable durante 200 ms y luego hace lo suyo.

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

Muchas gracias! está funcionando perfectamente para mí. – selegnasol

0

Comprobación de IE.readyState = READYSTATE_COMPLETE debería funcionar, pero no si eso demuestra confiable para usted y que, literalmente, quieren saber "el momento en que IE escribe 'Hecho' en su barra de estado", entonces usted puede hacer un bucle hasta IE.StatusText contiene "Hecho".

Cuestiones relacionadas