HTML - Как узнать, когда все кадры загружены? - PullRequest
11 голосов
/ 23 марта 2009

Я использую элемент управления .NET WebBrowser. Как узнать, когда веб-страница полностью загружена?

Я хочу знать, когда браузер больше не загружает данные. (Момент, когда IE пишет «Готово» в строке состояния ...).

Примечания:

  • События DocumentComplete / NavigateComplete могут происходить несколько раз для веб-сайта, содержащего несколько фреймов.
  • Состояние готовности браузера также не решает проблему.
  • Я попытался проверить количество кадров в коллекции кадров, а затем подсчитать, сколько раз я получаю событие DocumentComplete, но это тоже не работает.
  • this.WebBrowser.IsBusy тоже не работает. Это всегда «ложь» при проверке в обработчике «Полный документ».

Ответы [ 12 ]

2 голосов
/ 31 января 2010

Мой подход к выполнению чего-либо , когда страница полностью загружена (включая фреймы), выглядит примерно так:

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

Из других моих подходов я узнал некоторые "не" -s:

  • не пытайтесь согнуть ложку ...; -)
  • не пытайтесь создать сложную конструкцию, используя события DocumentComplete, Frames, HtmlWindow.Load. Ваше решение будет хрупким, если оно вообще будет работать.
  • не используйте System.Timers.Timer вместо Windows.Forms.Timer, странные ошибки начнут появляться в странных местах, если вы это сделаете, из-за таймера, работающего в другом потоке, чем остальная часть вашего приложения.
  • не используйте только Timer без DocumentComplete, потому что он может сработать до того, как ваша страница даже начнет загружаться, и выполнит ваш код преждевременно.
2 голосов
/ 13 апреля 2010

Вот моя проверенная версия. Просто сделайте это DocumentCompleted Event Handler и поместите код, который вы хотите, чтобы он назывался , один раз в метод OnWebpageReallyLoaded(). По сути, этот подход определяет, когда страница была стабильной в течение 200 мс, а затем делает свое дело.

// 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 */
}
2 голосов
/ 25 февраля 2010

Вот как я решил проблему в своем приложении:

private void wbPost_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url != wbPost.Url)
        return;
    /* Document now loaded */
}
1 голос
/ 26 марта 2009

Вот что наконец-то сработало для меня:

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

На каждом событии завершения документа я запускаю все элементы html и проверяю все доступные кадры (я знаю, что это можно оптимизировать). Для каждого кадра я проверяю его состояние готовности. Это довольно надежно, но, как сказал Джеффамафон, я уже видел сайты, которые вызывали некоторые внутренние обновления. Но приведенный выше код удовлетворяет моим потребностям.

Редактировать: каждый кадр может содержать кадры внутри него, поэтому я думаю, что этот код следует обновить, чтобы рекурсивно проверять состояние каждого кадра.

0 голосов
/ 03 ноября 2011

Проверка на IE.readyState = READYSTATE_COMPLETE должна работать, но если это не является надежным для вас, и вы буквально хотите знать «момент, когда IE пишет« Done »в его строке состояния», то вы можете сделать цикл до IE .StatusText содержит «Done».

0 голосов
/ 31 марта 2010

Я просто использую метод webBrowser.StatusText. Когда написано «Готово», все загружено! Или я что-то упустил?

0 голосов
/ 26 марта 2009

Вы получите событие BeforeNavigate и DocumentComplete для внешней веб-страницы, а также для каждого фрейма. Вы знаете, что вы сделали, когда вы получаете событие DocumentComplete для внешней веб-страницы. Вы должны иметь возможность использовать управляемый эквивалент IWebBrowser2 :: TopLevelContainer () , чтобы определить это.

Однако, будьте осторожны, сам сайт может вызывать больше переходов по фреймам в любое время, когда вы захотите, поэтому вы никогда не узнаете, действительно ли страница сделана навсегда. Лучшее, что вы можете сделать, - это вести подсчет всех видений BeforeNavigates и уменьшать их при получении DocumentComplete.

Редактировать: вот управляемые документы: TopLevelContainer .

0 голосов
/ 26 марта 2009

Можете ли вы использовать JQuery? Тогда вы можете легко связать готовые события с целевыми кадрами. См. этот ответ для указаний. Это сообщение в блоге также обсуждает это. Наконец, есть плагин , который вы можете использовать.

Идея состоит в том, что вы подсчитываете количество кадров на веб-странице, используя:

$("iframe").size()

и затем вы подсчитываете, сколько раз было запущено событие iframe.

0 голосов
/ 25 марта 2009

Я не уверен, что это сработает, но попробуйте добавить событие JavaScript «onload» в ваш набор фреймов следующим образом:

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 голосов
/ 23 марта 2009

У меня нет альтернативы для вас, но мне интересно, является ли свойство IsBusy tru e во время обработки документа завершено, потому что обработчик все еще работает и, следовательно, элемент управления WebBrowser технически все еще ' занят».

Самым простым решением было бы иметь цикл, который выполняется каждые 100 мс или около того, пока не будет сброшен флаг IsBusy (с максимальным временем выполнения в случае ошибок). Это, конечно, предполагает, что IsBusy не будет установлен на false в любой момент загрузки страницы.

Если обработчик Document Complete выполняется в другом потоке, вы можете использовать блокировку, чтобы перевести основной поток в спящий режим и разбудить его из потока Document Complete. Затем проверьте флаг IsBusy, блокируя основной поток по-прежнему true.

...