WPF中使用WebView2控件
WebView2简介
概述
WebView2 全称 Microsoft Edge WebView2 控件,此控件的作用是在本机桌面应用中嵌入web技术(html,css,javascript),从名字就可以看出来WebView2使用了Edge内核渲染web内容。
通俗来说,WebView2控件是一个UI组件,允许在桌面应用中提供web能力的集成,即俗称的混合开发。
优势
- 助力程序开发和维护:相比桌面应用开发,一般来说web技术更加的灵活
- 无需升级:以往增加了新功能都需要升级客户现场的桌面应用程序,引入web技术之后,省去了升级的烦恼
- 扩展web应用:补足了web技术的短板,不能或者很难和宿主机交互,访问操作系统api。
支持的运行时平台
- Win32 C/C++
- .NET Framework 4.5 或更高版本
- .NET Core 3.1 或更高版本
- .NET 5
- .NET 6
- WinUI 2.0
- WinUI 3.0
进程模型
当在WPF程序中引入 WebView2 控件后,WPF程序和WebView2控件的进程模型如下:

- WPF程序进程和WebView2控件是进程隔离的
- 维护WebView2运行的实际是一组进程
基本使用
本文代码基于 .NetFramework 4.8
安装WebView2运行时
开发之前需要先安装WebView2的运行时。
同理,当程序开发完毕,在客户机器上面部署WPF应用程序的时候也应该先安装WebView2运行时,此部分将放在部署环节详细讨论。
有三种方式安装WebView2运行时:
- 常青版引导程序:就是一个小的引导程序,方便传输,但是下载的时候需要公网环境。WebView2运行时实际通过此引导程序完成安装。
- 常青版独立安装程序:完整安装包,可离线安装
- 已修复版本:特定版本安装
WebView2运行时下载:https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/
安装WebView2Sdk
通过 Nuget 安装
- 名字:Microsoft.Web.WebView2
- 安装命令:NuGet\Install-Package Microsoft.Web.WebView2 -Version 1.0.1518.46
- 作者:Microsoft
打开一个网页
新建WPF应用程序,并通过如下代码在Window中添加WebView2 XAML 的命名空间。
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
引入WebView2控件,并设置 Source 属性为 https://www.microsoft.com
<Grid>
<wv2:WebView2 Name="wv2" Source="https://www.microsoft.com" />
</Grid>
运行程序,将可以看到WPF程序中打开了巨硬官网

通过代码控制打开的网页
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.wv2.Source = new Uri("http://baidu.com");
}
导航事件
导航事件是巨硬官方的一个叫法,通俗来说就是在WebView2中打开一个网址的步骤。
打开一个网页的过程
- NavigationStarting:开始导航,导航生成网络请求。 主机可能会在事件期间禁止请求
- SourceChanged:开始导航,导航生成网络请求。 主机可能会在事件期间禁止请求
- ContentLoading:开始加载新页面的内容。
- HistoryChanged:历史记录更新
- BasicAuthenticationRequested
- DOMContentLoaded:完成对 DOM 内容的分析,但尚未完成加载页面上的所有图像、脚本和其他内容。
- NavigationCompleted:完成在新页面上加载内容。

可通过委托的方式拦截各个事件:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.wv2.Source = new Uri("http://baidu.com");
//this.wv2.Source = new Uri("about:blank");
//导航开始
this.wv2.NavigationStarting += wv2_NavigationStarting;
//源已经更改
this.wv2.SourceChanged += Wv2_SourceChanged;
//内容加载中
this.wv2.ContentLoading += Wv2_ContentLoading;
//导航结束
this.wv2.NavigationCompleted += Wv2_NavigationCompleted;
}
private void Wv2_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
{
throw new NotImplementedException();
}
private void Wv2_ContentLoading(object sender, CoreWebView2ContentLoadingEventArgs e)
{
throw new NotImplementedException();
}
private void Wv2_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e)
{
throw new NotImplementedException();
}
private void wv2_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
throw new NotImplementedException();
}
更改url的过程
更改url的过程依然遵循上述步骤,只是稍微复杂了一些.

空url
某些情况下,可能需要一个默认的页面,那么空url是一个很好的选择。
this.wv2.Source = new Uri("about:blank");
进阶使用
WPF和Web通信
概述
当web页面中点击一个按钮需要通知WPF宿主程序,或者向WPF传递一些指令和数据的时候,需要用到 postMessage 和 WebMessageReceived 。
postMessage 是 js 方法,位于 window.chrome.webview.postMessage ,当需要向WPF程序发送数据的时候,只需要调用此方法,并传递参数就可以。此方法仅在WebView2控件内部有用,在Edge中调用将报异常(Cannot read properties of undefined 'postMessage')
WebMessageReceived 是 c# 事件,位于 Microsoft.Web.WebView2.Wpf.WebView2。可通过委托此事件来接收web网页中发送过来的消息。
Html代码示例
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>TestWebView2</title>
</head>
<body>
</br></br></br></br></br>
<button type="button" onclick="postMsg()">给WPF宿主程序发送msg</button>
<script>
window.onload = function () {
//alert("onload-success");
}
function postMsg() {
var args = "msg ,from webView2";
window.chrome.webview.postMessage(args);
alert("发送成功,内容:" + args);
}
</script>
</body>
</html>
C#代码示例
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//this.wv2.Source = new Uri("http://baidu.com");
//this.wv2.Source = new Uri("about:blank");
this.wv2.Source = new Uri("file:///E:/code/WPF/ramble-wpf/RambleWPF/html/PostMessage.html");
this.wv2.WebMessageReceived += Wv2_WebMessageReceived;
}
private void Wv2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
//接收到的字符串
string msg = e.TryGetWebMessageAsString();
//接收到的json
string msgJson = e.WebMessageAsJson;
}
常见问题
解决程序安装到C盘导致Webview2无法打开网页问题
现象
如果将源代码放到C盘并在VS中调试或者将打包好的程序放到C盘启动,都会发生无法打开网页的问题。
原因
此问题的原因是文件权限问题,WebView2在工作的时候需要指定一个文件夹来存放临时文件和数据,即UserDataFloder,需要此文件夹的读写权限。若不显示指定udf,将会在程序启动文件同级目录新建一个 RambleWPF.exe.WebView2 的文件夹存放临时文件,RambleWPF为WPF应用程序的名字。
解决办法
解决办法有两个:
- 显示指定非系统盘下文件夹作为UDF。比如D:\wvUDF ,需要确保此盘符一定存在,还有特殊的情况,有些操作系统的系统盘可能不是C盘,而是D盘。
- 程序启动的时候修改默认UDF的文件夹权限,这个方法看起来有趣,但是可以做到一劳永逸,因为方法1总有破绽。
显示指定UDF
通过设置 WebView2控件的CreationProperties属性可以实现自定义UDF。
需要注意的是,必须在WebView2.CoreWebView2对象初始化之前设置UDF,那么CoreWebView2对象什么时候初始化呢?有以下方式:
- 在xaml中设置 WebView2 的Source 属性
- 在代码中手动设置 Source,如 this.wv2.Source= new Uri("http://baidu.com")
- 调用 WebView2.EnsureCoreWebView2Async 方法
示例代码如下:
public partial class WebView2Demo : Window
{
public WebView2Demo()
{
InitializeComponent();
InitializeAsync();
}
async void InitializeAsync()
{
wv2.CreationProperties = new Microsoft.Web.WebView2.Wpf.CoreWebView2CreationProperties
{
UserDataFolder = "D:\\A\\wvUDF"
};
await wv2.EnsureCoreWebView2Async();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.wv2.Source = new Uri("http://baidu.com");
}
}
提升默认UDF文件夹权限
在程序启动的时候提升默认UDF的读写权限
示例代码如下:
/// <summary>
/// 给 WebView2Bug.exe.WebView2 文件夹赋予写入权限
/// </summary>
private void InitWebView2DirAccess()
{
try
{
string path = AppDomain.CurrentDomain.BaseDirectory;
string webview2DataDir = path + "WebView2Bug.exe.WebView2";
DirectoryInfo dir = new DirectoryInfo(webview2DataDir);
System.Security.AccessControl.DirectorySecurity security = dir.GetAccessControl();
//给文件夹追加 Everyone 的写入权限
security.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule("Everyone", System.Security.AccessControl.FileSystemRights.Write, AccessControlType.Allow));
dir.SetAccessControl(security);
}
catch (Exception ex)
{
string msg = ex.Message;
}
}
上述代码有点偏激,仅作为参考,实际开发中,不应该为EveryOne 用户提升如此大的权限。
引用
WebView2运行时下载:https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/
官网教程:https://learn.microsoft.com/zh-cn/microsoft-edge/webview2/
C盘权限问题issues:https://github.com/MicrosoftEdge/WebView2Feedback/issues/3087
WPF中使用WebView2控件的更多相关文章
- 在WPF中使用WinForm控件方法
1. 首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,System.Windows.Forms.dll. 2. 在要使用WinForm控 ...
- WPF中的image控件的Source赋值
WPF中的Image控件Source的设置 1.XAML中 简单的方式(Source="haha.png"); image控件的Source设置为相对路径后(Source=&quo ...
- 在WPF中调用Winform控件
最近在项目中用到了人脸识别和指纹识别,需要调用外部设备和接口,这里就用到了在WPF中调用Winform控件. 第一步,添加程序集引用.System.Windows.Forms和WindowsForms ...
- WPF中的ControlTemplate(控件模板)(转)
原文地址 http://www.cnblogs.com/zhouyinhui/archive/2007/03/28/690993.html WPF中的ControlTemplate(控件模板) ...
- [转]在WPF中使用WinForm控件方法
本文转自:http://blog.csdn.net/lianchangshuai/article/details/6415241 下面以在Wpf中添加ZedGraph(用于创建任意数据的二维线型.条型 ...
- WPF中的ControlTemplate(控件模板)
原文:WPF中的ControlTemplate(控件模板) WPF中的ControlTemplate(控件模板) ...
- [转]WPF中的ControlTemplate(控件模板)
WPF中的ControlTemplate(控件模板) ...
- WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
在 WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit) 一文中,我们说到了在 WPF 中引入简单的 UWP 控件以及相关的注意事项 ...
- 在WPF中使用AForge控件
AForge.NET 是用C#写的一个关于计算机视觉和人工智能领域的框架,它包括图像处理.神经网络.遗传算法和机器学习等. 要实现视频功能,需要使用AForge.Controls命名空间中的Video ...
- 关于WPF中ItemsControl系列控件中Item不能继承父级的DataContext的解决办法
WPF中所有的集合类控件,子项都不能继承父级的DataContext,需要手动将绑定的数据源指向到父级控件才可以. <DataGridTemplateColumn Header="操作 ...
随机推荐
- DQL语句排序与分组
DQL语句排序与分组 一.DQL-排序 排序是计算机内经常进行的一种操作,其目的是将一组"无序"的记录序列调整为"有序"的记录序列.分内部排序和外部排序,若整个 ...
- 前后端分离项目(十一):实现"删"功能(前后端)
好家伙,本篇介绍如何实现"删"功能 来看效果, 数据库 (自然是没什么毛病) "增"搞定了,其实"删"非常简单 (我不会告诉你我是为了水一 ...
- 详细了解JVM运行时内存
详细了解JVM运行时内存 1.程序计数器 概念 程序计数器也叫作PC寄存器,是一块很小的内存区域,可以看做是当前线程执行的字节码的行号指示器.字节码的解释工作就是通过改变程序计数器里面的值来获得下一条 ...
- hadoop配置day01
hadoop 安装jdk 配置文件: sudo vim /etc/profile 配置文件: export JAVA_HOME=/home/hadoop/jvm/jdk1.8.0_341 export ...
- CC3
cc_link_three 0x00前言 这里要单独学cc链子三是因为它的调用方式不是执行命令而是代码执行,是一种动态类加载机制来执行代码,然后类加载的时候要用类加载器 0x01开整 首先明白调用机制 ...
- WPF之lognet4的基本使用
log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文介绍lognet4的基本使用. 第一步:新 ...
- Go语言核心36讲09
从本篇文章开始,我们正式进入了模块2的学习.在这之前,我们已经聊了很多的Go语言和编程方面的基础知识,相信你已经对Go语言的开发环境配置.常用源码文件写法,以及程序实体(尤其是变量)及其相关的各种概念 ...
- phpword 模板文件导出word到服务器 并浏览器下载
模板文件填充 然后生成新文件 //调用PHPwordrequire_once(ROOTPATH . "inc/vendor/autoload.php"); $phpWord = n ...
- vue 中使用 this 更新数据的一次大坑
情景说明: 之前用 vue 做数据绑定更新时,发现一个莫名奇妙的问题. 我在 vue 实例中声明了一个数组属性如 books: [],在异步请求的回调函数中使用 this.books = res.da ...
- [论文阅读] 颜色迁移-N维pdf迁移
[论文阅读] 颜色迁移-N维pdf迁移 文章: N-Dimensional Probability Density Function Transfer and its Application to C ...