将JavaScript Office插件转为可安装插件时的对话框功能问题
解决方案:VSTO+WebView2环境下替代Office对话框API实现外部窗口与回调
VSTO插件中的WebView2控件属于独立嵌入式浏览器环境,无法直接调用Office Web加载项专属的Office.context.ui API。要实现需求,需通过VSTO原生窗口承载WebView2替代Office对话框,并利用WebView2的消息机制完成任务窗格与外部窗口的通信。
一、实现外部窗口的创建与导航
1. 准备VSTO端基础代码
在VSTO项目中添加WinForm窗口(命名为AuthDialogForm),并安装Microsoft.Web.WebView2 NuGet包。在任务窗格后台代码中注册JS可调用的.NET方法,用于触发窗口打开:
private void TaskPane_Load(object sender, EventArgs e) { webView2.CoreWebView2InitializationCompleted += async (s, args) => { // 注册供JS调用的.NET对象 webView2.CoreWebView2.AddHostObjectToScript("DialogHelper", new DialogHelper(this)); // 注入脚本让JS能访问该对象 await webView2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(@" window.dialogHelper = window.chrome.webview.hostObjects.sync.DialogHelper; "); }; } [ComVisible(true)] public class DialogHelper { private readonly YourTaskPaneControl _taskPane; public DialogHelper(YourTaskPaneControl taskPane) { _taskPane = taskPane; } public void OpenAuthDialog(string url) { var dialogForm = new AuthDialogForm(url); dialogForm.Show(); } }
2. 外部窗口加载目标URL
在AuthDialogForm中初始化WebView2并导航到指定页面,同时注册消息接收事件:
public partial class AuthDialogForm : Form { public AuthDialogForm(string url) { InitializeComponent(); webView2.CoreWebView2InitializationCompleted += (s, args) => { webView2.CoreWebView2.Navigate(url); // 监听页面发送的消息 webView2.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived; }; webView2.EnsureCoreWebView2Async(); } private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e) { var message = e.WebMessageAsJson; // 将消息转发给任务窗格的WebView2 Globals.ThisAddIn.TaskPaneWebView.CoreWebView2.PostWebMessageAsString(message); // 处理关闭指令 if (message.Contains("\"message\":\"close\"")) { this.Close(); } } }
3. 任务窗格JS触发窗口打开
替换原来的displayDialogAsync调用,改为调用.NET注册的方法:
document.getElementById('authBtn').addEventListener('click', () => { window.dialogHelper.OpenAuthDialog('https://www.ourfrontend.com/auth/google'); });
二、实现窗口操作后的回调触发
1. 外部页面发送消息
在外部页面(https://www.ourfrontend.com/auth/google)中,完成操作后通过WebView2 API发送消息:
// 触发用户信息回调 async function sendUserInfo() { const token = await getSignTokenLocal(); const payload = payloadFromToken(token); window.chrome.webview.postMessage({ message: 'getUser', payload: payload }); } // 触发窗口关闭 function closeWindow() { window.chrome.webview.postMessage({ message: 'close' }); }
2. 任务窗格JS处理回调
在任务窗格页面中监听WebView2的消息事件,执行原有的回调逻辑:
window.chrome.webview.addEventListener('message', (event) => { const msg = event.data; if (msg.message === 'getUser') { resolve(msg.payload); } });
关键注意事项
- 所有供JS调用的.NET类必须标记
[ComVisible(true)]。 - WebView2初始化需异步完成,避免空引用错误。
- 消息建议使用JSON格式,便于结构化数据传输。
内容的提问来源于stack exchange,提问作者SoftTimur
相关产品推荐
相关产品推荐

