C# Windows Forms: встроенный браузер без падений
Суть проблемы состоит в том, что браузерная компонента WebBrowser позволяет работать с содержимым страницы только после полной загрузки её DOM. Многие начинающие разработчики не учитывают этого и их программы с встроенным браузером "падают" немедленно после попытки получить элемент со страницы:
WebBrowser w = new WebBrowser(); w.Url = new Uri("https://google.com"); var e = w.Document.GetElementById ("elementId");
Скорее всего, здесь w.Document
равен null
, потому что переход браузера на новую страницу выполняется асинхронно, а строчка три сработает сразу после второй без ожидания загрузки страницы. Можно сделать вот так:
WebBrowser w = new WebBrowser(); public Form1() { InitializeComponent(); w.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler (w_DocumentCompleted); w.Url = new Uri("https://google.com"); } void w_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { var e = w.Document.GetElementById("elementId"); }
а ещё лучше применить вспомогательную функцию OpenUri
(см. в коде), которую можно вызывать, если при старте программы требуется загрузка web-страницы.
Создав проект C# Windows Forms, добавим на форму компоненты WebBrowser
и TextBox
с именами по умолчанию. Для реализации как автоматического сбора информации со страницы, загружаемой при старте приложения, так и перехода на страницу, адрес которой введён в TextBox
, нам понадобилось запрограммировать только следующие события:
Form1
(конструктор формы) - вызываемOpenUri
и разбираем другой вспомогательной функциейPrintDom
структуру документа на заданную глубину (в демо-целях выводится окно сообщенияMessageBox
). Также показано, как после вызоваOpenUri
извлечь отдельный элемент;textBox1_KeyDown
- по нажатию Enter в текстовом поле пытаемся минимально грамотно проверить, является строка вTextBox
адресом и затем переходим на неё;textBox1_Click
- по клику в текстовом поле выделяем его содержимое, чтобы сразу можно было вводить новый адрес.
OpenUri
- ожидание загрузки страницы с заданным адресом. Кстати, в теле функции есть ответ на ещё один частый вопрос - "Как убрать сообщения об ошибках сценария при работе сWebBrowser
?";PrintDom
- cканируем DOM на заданную глубинуdepth
и собираем всю информацию в строку.
Вот полный исходник файла Form1.cs
и проект для скачивания.
using System; using System.Windows.Forms; namespace MiniBrowser { public partial class Form1 : Form { public Form1 () { InitializeComponent (); OpenUri (textBox1.Text); //Ждём загрузки страницы! //Теперь можно получить элементы со страницы: HtmlDocument doc = webBrowser1.Document; if (doc != null) { HtmlElementCollection elemColl = doc.GetElementsByTagName ("HTML"); String str = PrintDom (elemColl, new System.Text.StringBuilder (), 1); MessageBox.Show ("DOM=" + str, "Тест Google", MessageBoxButtons.OK); } //Или конкретный элемент: /* HtmlElement el = webBrowser1.Document.GetElementById ("elementId"); if (el != null) { MessageBox.Show ("Элемент="+ el.ToString (), "Тест Google", MessageBoxButtons.OK); } */ } private void textBox1_KeyDown (object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { string url = textBox1.Text.Trim (); if (String.IsNullOrEmpty (url)) return; if (url.Equals ("about:blank")) return; //На пустое переходить не надо if (!url.StartsWith ("http://") && !url.StartsWith ("https://")) { //Дописать протокол по умолчанию url = "http://" + url; } Uri test = new Uri (url); if (Uri.TryCreate (url, UriKind.RelativeOrAbsolute, out test)) { try { webBrowser1.Navigate (test); } catch (System.UriFormatException ex) { MessageBox.Show (ex.Message, "Ошибка", MessageBoxButtons.OK); return; } } } } private void textBox1_Click (object sender, EventArgs e) { textBox1.SelectAll (); } private string PrintDom (HtmlElementCollection elemColl, System.Text.StringBuilder returnStr, Int32 depth) { //Сканируем DOM на заданную глубину depth System.Text.StringBuilder str = new System.Text.StringBuilder (); foreach (HtmlElement elem in elemColl) { string elemName; elemName = elem.GetAttribute ("ID"); if (elemName == null || elemName.Length == 0) { elemName = elem.GetAttribute ("name"); if (elemName == null || elemName.Length == 0) { elemName = "<no name>"; } } str.Append (' ', depth * 4); str.Append (elemName + ": " + elem.TagName + "(Level " + depth + ")"); returnStr.AppendLine (str.ToString ()); if (elem.CanHaveChildren) { PrintDom (elem.Children, returnStr, depth + 1); } str.Remove (0, str.Length); } return returnStr.ToString (); } private void OpenUri (string uri) { webBrowser1.ScriptErrorsSuppressed = true; //Убрать сообщения об ошибках сценария webBrowser1.Url = new Uri (uri); while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents (); //Выполняем другие события, пока страница не загрузилась } } } }
Скачать проект C# Windows Forms "MiniBrowser" в архиве .zip, развернуть в новую папку (12 Кб)

Скриншот приложения в работе
07.11.2024, 15:02 [79 просмотров]