WPF中使用WebView2控件的方法及常見問題
WebView2簡介
概述
WebView2 全稱 Microsoft Edge WebView2 控件,此控件的作用是在本機桌面應用中嵌入web技術(html,css,javascript),從名字就可以看出來WebView2使用了Edge內核渲染web內容。
通俗來說,WebView2控件是一個UI組件,允許在桌面應用中提供web能力的集成,即俗稱的混合開發(fā)。
優(yōu)勢
- 助力程序開發(fā)和維護:相比桌面應用開發(fā),一般來說web技術更加的靈活
- 無需升級:以往增加了新功能都需要升級客戶現(xiàn)場的桌面應用程序,引入web技術之后,省去了升級的煩惱
- 擴展web應用:補足了web技術的短板,不能或者很難和宿主機交互,訪問操作系統(tǒng)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運行時
開發(fā)之前需要先安裝WebView2的運行時。
同理,當程序開發(fā)完畢,在客戶機器上面部署WPF應用程序的時候也應該先安裝WebView2運行時,此部分將放在部署環(huán)節(jié)詳細討論。
有三種方式安裝WebView2運行時:
- 常青版引導程序:就是一個小的引導程序,方便傳輸,但是下載的時候需要公網(wǎng)環(huán)境。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
打開一個網(wǎng)頁
新建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程序中打開了巨硬官網(wǎng)
通過代碼控制打開的網(wǎng)頁
private void Window_Loaded(object sender, RoutedEventArgs e) { ????this.wv2.Source = new Uri("http://baidu.com"); }
導航事件
導航事件是巨硬官方的一個叫法,通俗來說就是在WebView2中打開一個網(wǎng)址的步驟。
打開一個網(wǎng)頁的過程
- NavigationStarting:開始導航,導航生成網(wǎng)絡請求。 主機可能會在事件期間禁止請求
- SourceChanged:開始導航,導航生成網(wǎng)絡請求。 主機可能會在事件期間禁止請求
- 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; ? ? //源已經(jīng)更改 ? ? 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傳遞一些指令和數(shù)據(jù)的時候,需要用到 postMessage 和 WebMessageReceived 。
postMessage 是 js 方法,位于 window.chrome.webview.postMessage ,當需要向WPF程序發(fā)送數(shù)據(jù)的時候,只需要調用此方法,并傳遞參數(shù)就可以。此方法僅在WebView2控件內部有用,在Edge中調用將報異常(Cannot read properties of undefined 'postMessage')
WebMessageReceived 是 c# 事件,位于 Microsoft.Web.WebView2.Wpf.WebView2??赏ㄟ^委托此事件來接收web網(wǎng)頁中發(fā)送過來的消息。
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宿主程序發(fā)送msg</button> ? ? <script> ? ? ? ? window.onload = function () { ? ? ? ? ? ? //alert("onload-success"); ? ? ? ? } ? ? ? ? function postMsg() { ? ? ? ? ? ? var args = "msg ,from webView2"; ? ? ? ? ? ? window.chrome.webview.postMessage(args); ? ? ? ? ? ? alert("發(fā)送成功,內容:" + 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無法打開網(wǎng)頁問題
現(xiàn)象
如果將源代碼放到C盤并在VS中調試或者將打包好的程序放到C盤啟動,都會發(fā)生無法打開網(wǎng)頁的問題。
原因
此問題的原因是文件權限問題,WebView2在工作的時候需要指定一個文件夾來存放臨時文件和數(shù)據(jù),即UserDataFloder,需要此文件夾的讀寫權限。若不顯示指定udf,將會在程序啟動文件同級目錄新建一個 RambleWPF.exe.WebView2 的文件夾存放臨時文件,RambleWPF為WPF應用程序的名字。
解決辦法
解決辦法有兩個:
- 顯示指定非系統(tǒng)盤下文件夾作為UDF。比如D:\wvUDF ,需要確保此盤符一定存在,還有特殊的情況,有些操作系統(tǒng)的系統(tǒng)盤可能不是C盤,而是D盤。
- 程序啟動的時候修改默認UDF的文件夾權限,這個方法看起來有趣,但是可以做到一勞永逸,因為方法1總有破綻。
顯示指定UDF
通過設置 WebView2控件的CreationProperties屬性可以實現(xiàn)自定義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; ? ? } }
上述代碼有點偏激,僅作為參考,實際開發(fā)中,不應該為EveryOne 用戶提升如此大的權限。
引用
WebView2運行時下載:https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/
官網(wǎng)教程:https://learn.microsoft.com/zh-cn/microsoft-edge/webview2/
C盤權限問題issues:https://github.com/MicrosoftEdge/WebView2Feedback/issues/3087
總結
到此這篇關于WPF中使用WebView2控件的文章就介紹到這了,更多相關WPF使用WebView2控件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C#打印類PrintDocument、PrintDialog、PrintPreviewDialog使用示例
這篇文章主要介紹了C#打印類PrintDocument、PrintDialog、PrintPreviewDialog使用示例,本文分別給出了示例代碼,需要的朋友可以參考下2015-06-06C#?wpf使用DockPanel實現(xiàn)制作截屏框
做桌面客戶端的時候有時需要實現(xiàn)截屏功能,能夠在界面上框選截屏,本文就來為大家介紹一下wpf如何使用DockPanel制作截屏框吧,感興趣的可以了解下2023-09-09C#使用NPOI將List數(shù)據(jù)導出到Excel文檔
這篇文章主要為大家詳細介紹了C#使用NPOI將List數(shù)據(jù)導出到Excel文檔,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02C#線性漸變畫刷LinearGradientBrush用法實例
這篇文章主要介紹了C#線性漸變畫刷LinearGradientBrush用法,實例分析了線性漸變畫刷LinearGradientBrush的相關使用技巧,需要的朋友可以參考下2015-06-06Unity Shader實現(xiàn)動態(tài)霧效果
這篇文章主要為大家詳細介紹了Unity Shader實現(xiàn)動態(tài)霧效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-04-04