VSTO Outlook插件内使用WebView2控件时的异步代码问题
解决方案:Outlook VSTO Send事件中同步调用WebView2 ExecuteScriptAsync方法
核心问题原因
- Outlook的
ItemEvents_10_SendEventHandler是同步回调,ref参数Cancel必须在回调返回前完成赋值,无法在异步上下文中操作 - WebView2的
CoreWebView2所有接口仅能在创建它的UI线程执行,直接跨线程调用就会抛出CoreWebView2 can only be accessed from the UI thread.错误 - 直接使用
.Wait()、.Result同步等待异步方法,会因为UI线程上下文阻塞触发死锁
可行实现方案
实现原理:提前缓存UI线程调度器,将WebView2异步操作封送到UI线程执行,同时通过消息泵送避免同步等待导致的死锁。
- 首先在WebView2所在的窗体/用户控件初始化阶段,缓存当前UI线程的Dispatcher:
// 提前声明全局变量 private Dispatcher _uiDispatcher = Dispatcher.CurrentDispatcher;
- Send事件处理逻辑如下:
private void ItemEvents_10_SendEventHandler(ref bool Cancel) { bool isScriptExecuted = false; string jsExecutionResult = string.Empty; // 将WebView2操作封送到UI线程执行 _uiDispatcher.Invoke(async () => { try { // 替换为你需要执行的JS脚本 jsExecutionResult = await webView2Control.CoreWebView2.ExecuteScriptAsync("yourCustomJSFunction()"); } catch (Exception ex) { // 自定义异常处理逻辑,例如日志打印 System.Diagnostics.Debug.WriteLine($"JS执行异常: {ex.Message}"); } finally { isScriptExecuted = true; } }, System.Windows.Threading.DispatcherPriority.Normal); // 同步等待异步结果,同时泵送消息避免死锁 while (!isScriptExecuted) { System.Windows.Forms.Application.DoEvents(); // 降低循环CPU占用 System.Threading.Thread.Sleep(10); } // 根据JS返回结果设置Cancel值,以下为示例逻辑,可按需修改 if (jsExecutionResult.Trim('"') == "cancelSend") { Cancel = true; } }
注意事项
- 必须等待WebView2的
CoreWebView2InitializationCompleted事件触发完成后再执行上述逻辑,避免CoreWebView2为空报错 - 可按需添加超时判断逻辑,例如等待超过3秒就强制终止等待、设置Cancel为true,避免JS执行异常导致Outlook长时间无响应
- 本方案兼容你当前使用的WebView2 1.0.1020.30、VS2019、Outlook PIA 15环境,无需升级依赖
内容的提问来源于stack exchange,提问作者TomoP
相关产品推荐
相关产品推荐

