Xamarin.Forms (UWP) - 如何获取 WebView 的 DOM 作为 HTML 字符串?

标签 xamarin webview xamarin.forms uwp xamarin.uwp

在 Xamarin.Forms (UWP) 项目中,我有一个 WebView控制谁Source使用 HTML 字符串创建,如下所示:

var webview = new Xamarin.Forms.WebView
{
    Source = new HtmlWebViewSource
    {
        Html = "<html>....</html>"
    }
};

HTML 包含可在 <body> 内动态生成 HTML 的 JavaScript。 。这在屏幕上完美呈现。这意味着 WebView 能够理解使用 JavaScript 创建的 DOM。太棒了。

但现在我需要解析一些生成的 HTML,但我似乎只能访问作为源传入的原始 HTML 字符串,而不是最终生成的 DOM。

有没有办法将 JavaScript 生成并由 WebView 理解的 DOM 转换为字符串,以便我可以解析(使用 HTML Agility Pack 或 AngleSharp 等库)并提取 HTML 的一些片段?这可以位于 Xamarin.Forms 或 UWP(我的目标平台)中。

注意: 完全公开(如果它有帮助,并避免指责这是 XY problem ),我最终试图解决打印具有多个页面的 WebView 的问题UWP - 对此的研究信息非常稀疏。我有一个适用于不是使用 JavaScript 动态生成的 HTML 的解决方案 - 基本上我提取了代表可打印页面的 HTML 部分,并将它们添加为单独的页面以进行打印和打印预览。但正如前面提到的,我似乎无法解析动态生成的内容。

最佳答案

我的第一个想法是使用 Eval方法内置于 Xamarin.Forms 中,但后来我发现该方法不会返回任何内容,因此它仅适用于应用程序到 webview 的通信。

到目前为止,实现此目的最简单的方法是使用 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将从 Web View 返回 HTML 本身的函数。

您只需替换 WebView在 XAML 中使用我们的 ExtendedWebView并称之为 GetHtmlAsync需要时使用方法。

我唯一不喜欢这个解决方案的是 eventTask<string>返回类型,这很奇怪。实际上已经有事件的返回类型是不寻常的。更好的解决方案是将属性放入自定义 EventArgs native 控件将根据操作结果进行设置,但因为 InvokeScriptAsync方法是异步的(并且非异步 InvokeScript 方法已过时,不应再使用),我们必须实现自定义 Task当属性设置时,这将完成。这种方法在 UWP 中用于某些事件,它们使用“延迟”,这表示调用者只有在某些异步操作完成后事件才会完成。我将尝试寻找一些关于如何在自定义 View 的情况下调用 native 异步操作的权威答案:-)。

关于Xamarin.Forms (UWP) - 如何获取 WebView 的 DOM 作为 HTML 字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49921779/

相关文章:

android - "java.exe"在运行 xamarin.android 应用程序时退出并出现代码 1 错误

android - 从 webview 访问原生 android 方法

android - 缩小 Web View 的混合 Web 应用程序以匹配保持纵横比的屏幕宽度和高度

ios - 用于更改 iOS 中 slider 条粗细的 Xamarin Form slider 自定义

c# - 未找到方法 'SQLiteConnection.InsertAll'

ios - Visual Studio 中仅支持 ARM64 架构

ios - Xamarin iOS 项目引用绑定(bind)在 sim 上而不是在设备上启动

xamarin - 如何在我的 Xamarin Forms 应用程序上本地保存一些用户数据?

java - 在 WebView.replaceContent 中加载本地 CSS 文件

fonts - Xamarin 表单 - UWP 字体