WebView2 全稱 Microsoft Edge WebView2 控制元件,此控制元件的作用是在本機桌面應用中嵌入web技術(html,css,javascript),從名字就可以看出來WebView2使用了Edge核心渲染web內容。
通俗來說,WebView2控制元件是一個UI元件,允許在桌面應用中提供web能力的整合,即俗稱的混合開發。
當在WPF程式中引入 WebView2 控制元件後,WPF程式和WebView2控制元件的程序模型如下:
本文程式碼基於 .NetFramework 4.8
開發之前需要先安裝WebView2的執行時。
同理,當程式開發完畢,在客戶機器上面部署WPF應用程式的時候也應該先安裝WebView2執行時,此部分將放在部署環節詳細討論。
有三種方式安裝WebView2執行時:
WebView2執行時下載:https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/
通過 Nuget 安裝
新建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中開啟一個網址的步驟。
可通過委託的方式攔截各個事件:
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是一個很好的選擇。
this.wv2.Source = new Uri("about:blank");
當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網頁中傳送過來的訊息。
<!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>
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槽並在VS中偵錯或者將打包好的程式放到C槽啟動,都會發生無法開啟網頁的問題。
此問題的原因是檔案許可權問題,WebView2在工作的時候需要指定一個資料夾來存放臨時檔案和資料,即UserDataFloder,需要此資料夾的讀寫許可權。若不顯示指定udf,將會在程式啟動檔案同級目錄新建一個 RambleWPF.exe.WebView2 的資料夾存放臨時檔案,RambleWPF為WPF應用程式的名字。
解決辦法有兩個:
通過設定 WebView2控制元件的CreationProperties屬性可以實現自定義UDF。
需要注意的是,必須在WebView2.CoreWebView2物件初始化之前設定UDF,那麼CoreWebView2物件什麼時候初始化呢?有以下方式:
範例程式碼如下:
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的讀寫許可權
範例程式碼如下:
/// <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 使用者提升如此大的許可權。