Страницы

Поиск по вопросам

среда, 22 января 2020 г.

Как получить событие LoadCompleted контрола WebBrowser, не вставляя данный контрол в XAML?

#c_sharp #wpf #webbrowser


У меня нет потребности использовать 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 или не добавлен программным путем в качестве 
        // дочернего компонента к одному из существующих контролов окна.
    }        
}

    


Ответы

Ответ 1



Действительно, событие 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});

Комментариев нет:

Отправить комментарий