如果你正在开发WPF桌面应用,又需要嵌入网页内容,WebView2绝对值得考虑。作为微软新一代的网页嵌入控件,它基于Chromium内核,性能比老旧的WebBrowser控件强太多,而且比CefSharp更轻量。我最近在项目里用它替换了CefSharp,安装包直接从200MB瘦身到30MB,效果立竿见影。
先说说环境准备。WebView2需要Chromium内核支持,有三种方式获取:
推荐第二种方式,既不用强制用户换浏览器,又能自动更新内核。安装包可以从微软官网下载,大概100MB左右。
下面这段代码展示了最简单的WebView2使用:
xml复制<Window x:Class="WebView2Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:webView2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
Title="WebView2 Demo" Height="450" Width="800">
<Grid>
<webView2:WebView2 x:Name="webView" Source="https://www.bing.com"/>
</Grid>
</Window>
就这么简单!但别高兴太早,实际项目中你会遇到各种坑。比如这个Source属性设置看似简单,其实背后是隐式初始化,在某些复杂场景下可能会出问题。
WebView2的初始化有隐式和显式两种方式。新手最容易栽在显式初始化的异步问题上。看看这段典型错误代码:
csharp复制var env = await CoreWebView2Environment.CreateAsync();
await webView.EnsureCoreWebView2Async(env);
webView.CoreWebView2.Navigate("https://example.com"); // 这里会抛空引用异常!
为什么?因为EnsureCoreWebView2Async只是表示"开始初始化",而不是"初始化完成"。正确的做法是注册初始化完成事件:
csharp复制webView.CoreWebView2InitializationCompleted += (sender, e) => {
if(e.IsSuccess) {
webView.CoreWebView2.Navigate("https://example.com");
}
};
await webView.EnsureCoreWebView2Async();
初始化时还可以配置一些重要参数:
userDataFolder:设置缓存目录,不设置的话会存到临时目录browserExecutableFolder:指定Chromium内核路径options:环境选项,比如禁用GPU加速我建议把缓存目录放在AppData下,这样用户清理临时文件时不会误删重要数据:
csharp复制var cachePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MyApp",
"WebView2Cache"
);
WebView2的强大之处在于丰富的可定制性。下面这些设置我几乎每个项目都会用上:
csharp复制webView.CoreWebView2.Settings = {
AreDefaultContextMenusEnabled = false, // 禁用右键菜单
AreDevToolsEnabled = false, // 禁用F12开发者工具
IsZoomControlEnabled = false, // 禁用缩放
IsStatusBarEnabled = false // 隐藏状态栏
};
事件处理是另一个重头戏。常用的几个事件:
NavigationStarting:页面开始加载时触发NavigationCompleted:页面加载完成时触发WebMessageReceived:收到网页消息时触发NewWindowRequested:弹出新窗口时触发比如实现一个简单的URL安全检查:
csharp复制webView.CoreWebView2.NavigationStarting += (sender, e) => {
if(!e.Uri.StartsWith("https://")) {
e.Cancel = true;
webView.CoreWebView2.ExecuteScriptAsync(
$"alert('{e.Uri} 不是安全链接,请使用HTTPS!')"
);
}
};
与网页的交互是核心功能。WebView2支持双向通信:
下面是个完整示例:
csharp复制[ComVisible(true)]
public class JSBridge {
public string ProcessData(string input) {
return $"处理后的数据: {input.ToUpper()}";
}
}
// 注册对象
webView.CoreWebView2.AddHostObjectToScript("bridge", new JSBridge());
// 网页中调用
// const result = await chrome.webview.hostObjects.bridge.ProcessData('test');
部署时最大的优势是不用打包Chromium内核,只需确保目标机器安装了WebView2 Runtime。这段代码可以检查运行环境:
csharp复制public static bool CheckWebView2Installed() {
try {
var version = CoreWebView2Environment.GetAvailableBrowserVersionString();
return !string.IsNullOrEmpty(version);
} catch {
return false;
}
}
如果没安装,可以引导用户下载安装包(约100MB)。比起CefSharp动辄200MB的内核,这简直是空间拯救者。
但WebView2也不是完美的,最著名的就是WPF的UI层级问题。简单说就是WebView2会覆盖所有后续声明的控件,这个Bug困扰开发者很久。官方在2022年初的预览版中终于修复了,解决方案是设置DefaultBackgroundColor属性:
xml复制<webView2:WebView2 x:Name="webView"
Source="https://example.com"
DefaultBackgroundColor="Transparent"/>
其他常见问题:
我在项目迁移中还遇到一个坑:某些网页在CefSharp下正常,但在WebView2中样式错乱。最后发现是网页用了旧版Flex布局,通过强制Chromium兼容模式解决了:
csharp复制webView.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false;
webView.CoreWebView2.NavigateWithWebResourceRequest(
new CoreWebView2WebResourceRequest {
Uri = url,
Headers = $"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.62\r\n"
}
);
WebView2的更新很频繁,建议定期检查GitHub上的Release Notes。比如最近1.0.1245版本就修复了DPI缩放问题,这对高分屏用户很重要。