Xamarin.Forms (UWP) - Как я могу получить DOM WebView в виде строки HTML?
В проекте Xamarin.Forms (UWP) у меня есть WebView
контролировать чей Source
создается со строкой HTML, например так:
var webview = new Xamarin.Forms.WebView
{
Source = new HtmlWebViewSource
{
Html = "<html>....</html>"
}
};
HTML содержит JavaScript, который динамически генерирует HTML внутри <body>
, Это прекрасно отображает на экране. Это означает, что WebView понимает DOM, который создается с помощью JavaScript. Отлично.
Но теперь мне нужно проанализировать некоторые из сгенерированных HTML, но все, что мне может показаться, - это доступ к исходной строке HTML, которую я передал в качестве источника, а не к окончательному сгенерированному DOM.
Есть ли способ преобразовать DOM, сгенерированный JavaScript и понятый WebView, в строку, чтобы я мог проанализировать (используя библиотеку, такую как HTML Agility Pack или AngleSharp) и извлечь некоторые сегменты HTML? Это может быть в Xamarin.Forms или UWP (платформа, на которую я нацеливаюсь).
ПРИМЕЧАНИЕ. В полном раскрытии (если это помогает, и чтобы избежать обвинений в том, что это проблема XY), я в конечном итоге пытаюсь решить проблему печати WebView с несколькими страницами на UWP - исследования по этому вопросу встречаются очень редко Информация. У меня есть решение, которое работает для HTML, которое не генерируется динамически с помощью JavaScript - в основном я извлекаю части HTML, представляющие печатные страницы, и добавляю их как отдельные страницы для печати и предварительного просмотра. Но, как упоминалось ранее, я не могу разобрать динамически генерируемый контент.
1 ответ
Моей первой мыслью было использовать Eval
Метод встроен в Xamarin.Forms, но потом я узнал, что этот метод ничего не возвращает, поэтому он подходит только для связи между приложениями и веб-представлениями.
Пока что самый простой способ реализовать это - использовать пользовательскую версию WebView
управления:
public class ExtendedWebView : WebView
{
public delegate Task<string> GetHtmlRequestedHandler();
public event GetHtmlRequestedHandler GetHtmlRequested;
public async Task<string> GetHtmlAsync()
{
var handler = GetHtmlRequested;
if (handler != null)
{
return await handler.Invoke();
}
return null;
}
}
Теперь в проекте платформы UWP создайте пользовательский рендер:
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace App.UWP
{
public class ExtendedWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
var ew = (e.OldElement as ExtendedWebView);
ew.GetHtmlRequested -= Ew_GetHtmlRequested;
}
if (e.NewElement != null)
{
var ew = (e.NewElement as ExtendedWebView);
ew.GetHtmlRequested += Ew_GetHtmlRequested;
}
}
private async Task<string> Ew_GetHtmlRequested()
{
return await Control.InvokeScriptAsync("eval", new string[] { "document.documentElement.outerHTML;" });
}
}
}
Хитрость в том, что мы вызываем JavaScript eval
функция, которая будет возвращать сам HTML из веб-представления.
Вам просто нужно заменить WebView
в XAML с нашими ExtendedWebView
и назовите его GetHtmlAsync
метод всякий раз, когда это необходимо.
Единственное, что мне не нравится в этом решении, это то, что event
имеет Task<string>
возвращаемый тип, что странно. На самом деле уже наличие типа возврата для события является необычным. Лучшим решением было бы поместить свойство в обычай EventArgs
что родной элемент управления будет установлен с результатом операции, но потому что InvokeScriptAsync
метод асинхронный (и не асинхронный InvokeScript
метод устарел и больше не должен использоваться) нам придется реализовать Task
это будет завершено, когда свойство установлено. Такой подход используется в UWP с некоторыми событиями, они используют "отсрочку", которая говорит вызывающей стороне, что событие завершится только после завершения некоторой асинхронной операции. Я попытаюсь найти какой-нибудь авторитетный ответ о том, как вызывать собственную асинхронную операцию в случае пользовательских представлений:-) .