WebView2:从Javascript代码在C#中设置对象属性
c#
这是这个问题的后续。
我正在将 WPF 应用程序从 CEFSharp 移植到 WebView2。我有一个 HostObject 需要从 WebView2 窗口中的 js 访问。就是这样,脱光了。
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());
我可以像这样检索公共属性和成员。到现在为止还挺好。
webView.CoreWebView2.AddHostObjectToScript("api", new API());
我的问题:我可以在没有任何异步竞争条件或死锁风险的情况下可靠地设置这样的属性吗? api.Username = 'whoever'它似乎有效,但我还没有发现它记录在案。
(async function foo () {
const api = chrome.webview.hostObjects.api
const ver = await api.Version
alert (ver)
})();
文档说 HostObject 是通过 Promises 公开的。我是否正确击中二传手?
回答
当您在 JavaScript 代理上为通过 CoreWebView2.AddHostObjectToScript 创建的宿主对象设置属性时,与获取属性或调用方法不同,赋值返回与赋值相同的值,而不是表示该赋值完成的承诺。属性分配确实会生成一条消息发送回 WebView2 主机应用程序进程,并且属性将被分配,您只是不会承诺在完成时告诉您。
设置主机属性
或者,您可以使用setHostProperty,该方法将执行属性分配并返回将在属性分配完成时解决的承诺。
(async function foo () {
const api = chrome.webview.hostObjects.api
await api.setHostProperty('Username', 'whoever');
const user = await api.Username
alert (user)
})();
同步代理
还有代理的同步版本。在异步代理返回承诺的任何地方,同步代理都会阻止 JavaScript 线程等待来自 WebView2 主机进程的响应。通常你不想阻塞等待跨进程调用的 JavaScript 线程,但在某些情况下它可能更实用或可接受。异步代理有一个sync方法可以返回代理的同步版本(异步)。
(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 主机应用程序进程中的同一个线程上处理,因此可能使用属性设置器而不是等待它完成然后调用 getter 仍然会强制执行获取消息以等待设置完成并且您的原始代码没问题。