WebView2:使用 Javascript 代码在 C# 中设置对象属性

WebView2: Setting object properties in C# from Javascript code

这是 的后续内容。

我正在将 WPF 应用程序从 CEFSharp 移植到 WebView2。我有一个需要从 WebView2 window 中的 js 访问的 HostObject。就是这样,精简了。

using System;
using System.Runtime.InteropServices;

namespace webview2Demo
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class Api
    {
        public string Username { get; set; }
        public string Version = "1.1.1";
        public Api()  //ctor
        {
        }
    }
}

我可以在 WebView2 控件的 NavigationStarting 事件中成功使用这一行,使对象在 Javascript 中可见。到目前为止一切顺利。

webView.CoreWebView2.AddHostObjectToScript("api", new API());

我可以像这样检索 public 属性和成员。到目前为止一切顺利。

(async function foo () {
  const api = chrome.webview.hostObjects.api
  const ver = await api.Version
  alert (ver)
})();

我的问题:在没有任何异步竞争条件或死锁风险的情况下,我能否像这样可靠地设置属性? api.Username = 'whoever' 它似乎有效,但我还没有找到它的文档。

(async function foo () {
  const api = chrome.webview.hostObjects.api
  api.Username = 'whoever'
  const user = await api.Username
  alert (user)
})();

文档说 HostObject 是通过 Promises 公开的。 我 setter 打对了吗?

当您在 JavaScript 代理上为通过 CoreWebView2.AddHostObjectToScript 创建的主机对象设置 属性 时,与获取 属性 或调用方法不同,赋值 returns 与分配的值相同,而不是表示完成该分配的承诺。 属性 分配确实会生成一条消息发送回 WebView2 主机应用程序进程,并且 属性 将被分配,您只是无法承诺在完成时告诉您。

设置主机属性

或者,您可以使用 setHostProperty,一种将执行 属性 赋值的方法和 return 将在 属性 赋值完成时解析的承诺。

(async function foo () {
  const api = chrome.webview.hostObjects.api
  await api.setHostProperty('Username', 'whoever');
  const user = await api.Username
  alert (user)
})();

同步代理

还有代理的同步版本。到处都是异步代理 return 承诺同步代理会阻止 JavaScript 线程等待来自 WebView2 主机进程的响应。通常您不想阻塞等待跨进程调用的 JavaScript 线程,但在某些情况下它可能更实用或更可接受。异步代理有一个 sync 方法,它将 return 代理的同步版本(异步)。

(async function foo () {
  // Note the one await call to get from async proxies to sync proxies
  const syncHostObjects = await chrome.webview.hostObjects.sync;
  const api = syncHostObjects.api;
  api.Username = 'whoever';
  const user = api.Username
  alert (user)
})();

依赖队列

由于所有 JavaScript 代理消息都在同一个队列中传输,并且必须在 WebView2 主机应用程序进程中的同一个线程上处理,因此可能需要使用 属性 setter 而不是等待它完成然后调用 getter 仍然会强制获取消息等待设置完成并且您的原始代码没问题。