C#: Событие загрузки страницы WebBrowser или как дождаться WebBrowser.ReadyState.Complete

Сегодня небольшая заметка будет просвещенна компоненту winforms с помощью которого можно имитировать Интернет браузер. Для тех кто не догадался о каком контроле идет речь — это элемент управления WebBrowser.
Контрол WebBrowser можно использовать для решения большого круга задач. Одной из основных таких задач является парсинг информации с веб ресурсов и автоматизация различных рутинных действий.
Главной особенностью элемента управления WebBrowser является тот факт, что работать с содержимым страницы можно только после полной загрузки DOM страницы. Многие начинающие разработчики сталкиваются с проблемой, когда после навигации браузера на указанный адрес, программа «падает» с ошибкой доступа к содержимому страницы. Например код ниже, будет генерировать такую ошибку:

WebBrowser w = new WebBrowser();
w.Url = new Uri("http://foolsoft.ru");
var e = w.Document.GetElementById("elementId");

Причина ошибки — w.Document равен null. Почему? Потому что вторая строчка инициирует переход браузера на новую страницу (асинхронно), однако строчка три выполняется сразу после второй (без ожидания загрузки страницы). Интернет страница грузится гораздо дольше чем выполняются строчки кода в программе. А значит программа выполнит строчку три до момента загрузки указанной страницы, что приводит к ошибке в работе. Для такого что бы избежать данной проблемы у контрола WebBrowser существует событие, которое вызывается после загрузки любой страницы. Называется данное событие DocumentCompleted. Пример:

WebBrowser w = new WebBrowser();

public Form1()
{
   InitializeComponent();
   w.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(w_DocumentCompleted);
   w.Url = new Uri("http://foolsoft.ru");
}

void w_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
   var e = w.Document.GetElementById("elementId");
}

Теперь мы можем получить доступ к нашей странице без ошибки, так как данный код выполниться только после полной ее загрузки. Данный подход отлично работает, однако если Вам нужно работать не с одной страницей, а с несколькими и выполнять разную логику, то данный поход будет не очень удобен. Причиной этого является то, что событие DocumentCompleted вызывается после загрузки любой страницы, но при этом Вы точно не знаете какой. Значит нужно добавлять дополнительный проверки на текущий Url страницы, что приводит к разрастанию кода и снижению его читаемости.
Однако есть еще один способ как можно открыть страницу в браузере, при этом дождавшись ее загрузки. Для этого напишем простую вспомогательную функцию:

private void OpenUri(string uri)
{
    w.Url = new Uri(uri);
    while (w.ReadyState != WebBrowserReadyState.Complete)
        Application.DoEvents(); //Выполняем другие события системы, пока страница не загрузилась 
}

Теперь можем работать с нашим WebBrowser следующим образом:

WebBrowser w = new WebBrowser();

public Form1()
{
   InitializeComponent();
   OpenUri("http://foolsoft.ru");
   var e = w.Document.GetElementById("elementId");
}

Вот и все. Надеюсь заметка была полезной 🙂

Запись опубликована в рубрике C# с метками , , , , , , , , , , , , , , . Добавьте в закладки постоянную ссылку.