У меня нет потребности использовать WebBrowser в XAML, мне он нужен всего лишь для того что бы иметь возможность вызвать событие Click на одном из тегов загруженной HTML страницы.
Я не могу вызывать событие Click на нужном мне теге, до того как загрузиться страница. Для того что бы получить уведомление о загрузке страницы мне нужно подписаться на событие LoadCompleted. Но, судя из того что я вижу событие LoadCompleted не генерируется пока WebBrowser не будет добавлен в XAML.
По причине того что я хочу осуществлять загрузку множества HTML страниц параллельно, перспектива постоянно добавлять WebBrowser контрол в разметку XAML до загрузки одной из множества страниц и удаление его из этой разметки после загрузки нужной страницы выглядит не очень удобно.
Моя цель получить доступ к вызову события Click на загруженной HTML странице без возни с ХАМL.
Можно ли получить доступ к событию LoadCompleted контрола WebBrowser без его привязки к XAML. Возможно ли это? Может быть есть какой то другой путь?
Код отражающий суть проблемы (WebBrowser в XAML не добавлялся)
public partial class SettingsWindow : Window
{
private WebBrowser browser = new WebBrowser();
public SettingsWindow()
{
InitializeComponent();
this.browser.LoadCompleted += Browser_LoadCompleted;
this.browser.Source = new Uri(@"https://www.google.com.ua/");
//this.browser.Navigate(path); <-- пробовал загружать страницу и этим способом.
}
private void Browser_LoadCompleted(object sender, NavigationEventArgs e)
{
// Этот обработчик никогда не вызывается если объект WebBrowser не
// добавлен в XAML или не добавлен программным путем в качестве
// дочернего компонента к одному из существующих контролов окна.
}
}
Ответ
Действительно, событие LoadCompleted для WPF WebBrowser не вызывается до тех пор, пока он не добавлен в какое-либо отображаемое окно или элемент управления, это известная проблема. Причина ее в том, как WebBrowser осуществляет инициализацию своего внутреннего ActiveX-элемента Internet Explorer, который и занимается загрузкой страницы. Это можно понять, посмотрев в его исходный код на Reference Source.
Для корректной работы события DocumentCompleted внутреннего ActiveX-объекта класс ActiveXHost должен быть переведен в состояние ActiveXState.InPlaceActive. По умолчанию он находится в ActiveXState.Running (см. инициализацию свойства), переход в состояние InPlaceActive происходит при вызове метода BuildWindowCore, который вызывается только при отображении родительского окна элемента. Это поведение отличается от аналогичного элемента в WinForms, который сразу переводится в InPlaceActive при инициализации, см. здесь)
Решение 1 - Использование WinForms WebBrowser
Элемент WebBrowser в WinForms избавлен от этой проблемы (аналогичное событие DocumentCompleted всегда вызывается), и функционально ни в чем не уступает элементу из WPF. Можно просто добавить ссылку на System.Windows.Forms и использовать его.
Решение 2 - Использование окна за пределами экрана
Для вызова BuildWindowCore требуется видимое окно, однако никто не запрещает сделать координаты отрицательными и поместить окно за пределы экрана:
Window wnd = new Window();
wnd.Content = browser;
wnd.ShowInTaskbar = false;
wnd.Top = -1000;
wnd.Left = -1000;
wnd.Width = 0;
wnd.Height = 0;
wnd.Show();
Решение 3 - Грязный хак с использованием отражения
Просто вызвать внутренний метод TransitionUpTo, передав в качества аргумента константу InPlaceActive (4):
using System.Reflection;
const int InPlaceActive = 4;
//...
var method = browser.GetType().GetMethod("TransitionUpTo",BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(browser, new object[] {InPlaceActive});
Комментариев нет:
Отправить комментарий