icpc 46 上海站 g題
本文將介紹如何在WinForms中嵌入WebView2,並講到WebView2的主要特徵。點選瞭解更多WebView2的API。
1. 準備
- Visual Studio 2017 及以上版本
- WebView2執行時,或者安裝Beta,Dev,Canary任一版本的 Microsoft Edge 預覽版。受支援的作業系統有:Windows 11\10\8.1\7
- 推薦使用82.0.488.0以上的Canary(日更)版本。
2. 建立單窗體應用
創那一個只包括主窗體的桌面專案:
- 開啟Visual Studio
- 依次點 檔案->新建->工程
- 點 建立新的工程
- 選擇 C# Windows Forms App (.NET Framework)
- 輸入 工程名稱 和 位置 ,在 Framework下拉列表中,選擇 ** .NET Framework 4.7.2** 或以上版本
- 點 建立
3. 安裝 WebView2 SDK
使用 NuGet 為工程新增 WebView2 SDK
- 在 Solution Explorer 右鍵點選工程名,在彈出選單中選擇 Manage NuGet Packages
- 點 Browse
- 選擇 Include prerelease(包含預覽版)
- 在查詢框中,輸入WebView2,在結果中選擇 Microsoft.Web.WebView2
- 選擇預設版本並點 Install
- 點 Ok
- 點 File > Save All (Ctrl+Shift+S) ,儲存工程
- 點 F5 編譯並執行後,程式的執行結果是一個空窗體
4. 建立一個WebView
在你的應用中新增一個WebView2控制元件。
- 點 Project > Add Form (Windows Forms)
- 在 Add New Item 視窗中,依次點 Visual C# Items > Web > Windows Forms > Form (Windows Forms) ,然後點 Add
- 點 View > Toolbox
- 在 Toolbox ,點開 WebView2 Windows Forms Control
注意:如果你用的是Visual Studio 2017,在Toolbox中預設是找不到WebView2控制元件的。若想讓其顯示,則需要依次選 Tools > Options > General 並且將 Automatically Populate Toolbox 設定為 true
- 把 WebView2 控制元件拖到 Form 窗體上。
- 在 Properties 工具框中,將 Name 屬性設定為 webView。可以使用 分類- 按字母排序 來找到需要的屬性
- WebView2的 Source 屬性用於初始化頁面的URI。將其值設定為:https://www.microsoft.com
- 點 File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行工程
- WebView2 控制元件中顯示如下:
注意:如果你的是高解析度顯示器,你需要為窗體應用設定置高解析度支援
5. 新增控制元件及處理窗體resize事件
從Toolbox中新增更多控制元件,並處理窗體的resize事件。
- 點 View > Toolbox
- 在 Toolbox 點 Common Controls
- 把 TextBox 拖動到窗體上
- 在 Properties屬性設定視窗,將Name 屬性設定為 addressBar
- 從 Toolbox 中拖動 Button 控制元件到窗體上
- 在Properties屬性設定視窗,將Name 屬性設定為 goButton
- 將Text屬性設定為 Go!
- 調整Button大小以適應文字
- 將文字框放在Button左側,並與按鈕文字對齊如下
- 重置窗體大小
- 點 View > Code 開啟窗體程式碼檔案。編寫
Form_Resize
函式處理窗體大小改變時,控制元件在恰當的位置。 - 刪除如下程式碼
public Form1()
{
InitializeComponent();
}
- 拷貝如下程式碼到剛刪除的程式碼的相同位置
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
}
private void Form_Resize(object sender, EventArgs e)
{
webView.Size = this.ClientSize - new System.Drawing.Size(webView.Location);
goButton.Left = this.ClientSize.Width - goButton.Width;
addressBar.Width = goButton.Left - addressBar.Left;
}
- 點**File > Save All (Ctrl+Shift+S) **儲存工程
-
F5編譯執行,效果如下:
6. 地址導航
在應用中新增位址列,讓使用者可以通過改變位址列來改變WebView2展示的內容。
- 在
Form1.cs
中新增CoreWebView2
名稱空間,程式碼如下:
using Microsoft.Web.WebView2.Core;
- 在窗體設計介面,雙擊Go按鈕,以在
Form1.cs
中新增goButton_Click
事件響應方法,將以下程式碼拷到方法中:
private void goButton_Click(object sender, EventArgs e)
{
if (webView != null && webView.CoreWebView2 != null)
{
webView.CoreWebView2.Navigate(addressBar.Text);
}
}
這樣,```goButton_Click```方法就實現了當使用者在位址列輸入地址並點選Go按鈕時,WebView2就將顯示址址欄中的地址所代表的頁面內容。
- 點 **File > Save All (Ctrl+Shift+S) **儲存工程
- F5編譯並執行
- 在位址列中輸入你想訪問的地址關點Go,驗證下視窗上顯示的是不是你想要的內容吧。
注意:在位址列中應輸入完整的URL,如果址址不是以http://
或https://
開頭的話,會遇到ArgumentException
異常
7. Navigation(導航) 事件
在頁面跳轉過程中,WebView2控制元件會發起一系列事件。而嵌入WebView2的應用會監聽到以下事件:
- NavigationStarting
- SourceChanged
- ContentLoading
- HistoryChanged
- NavigationCompleted
瞭解更多關於WebView2的導航事件
當一個錯誤發生時,會引發以下事件,可能取決於對錯誤網頁的導航 - SourceChanged
- ContentLoading
- HistoryChanged
以下操作,將為NavigationStarting委託註冊一個處理方法,處理當地址不是Https時,取消頁面請求。通過此例來展示如何使用這些事件。 - 在
Form1.cs
中,做如下程式碼更改,新增一個EnsureHttps
方法
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
webView.NavigationStarting += EnsureHttps;
}
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
if (!uri.StartsWith("https://"))
{
args.Cancel = true;
}
}
在建構函式中,EnsureHttps
被註冊為WebView2控制元件的NavigationStarting
的事件處理方法。
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 如果訪問HTTPS會開啟正常的頁面,如果是HTTP則不會正常訪問
8. 指令碼
主程式可以在執行時向WebView2注入JavaScript指令碼。可以讓WebView2執行任意的JavaScript,或者新增初始化指令碼。注入的JavaScript適用於所有新的頂層文件和任何子框架,直到JavaScript被刪除。注入的 JavaScript 以特定的時間執行。
- 在建立全域性物件後執行注入的JavaScript。
- 在執行HTML文件中包含的任何其他指令碼之前執行注入的JavaScript。
1.例如,在使用者導航到非 HTTPS 站點時,添加發送警報的指令碼。修改EnsureHttps
函式,使用ExecuteScriptAsync
方法將指令碼注入到網頁內容中,如下圖所示
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
if (!uri.StartsWith("https://"))
{
webView.CoreWebView2.ExecuteScriptAsync($"alert('{uri} is not safe, try an https link')");
args.Cancel = true;
}
}
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 應用在訪問非 HTTPS 的網站時顯示警報
9. 宿主程式與頁面之間的通訊
宿主程式和頁面內容可以使用 postMessage
進行通訊如下:
- WebView2 控制元件中的 Web 內容可以使用
window.chrome.webview.postMessage
向宿主程式釋出訊息。宿主程式使用任何註冊到WebMessageReceived
委託方法處理訊息。 - 主程式使用
CoreWebView2.PostWebMessageAsString
或CoreWebView2.PostWebMessageAsJSON
將訊息釋出到 WebView2 控制元件中的 Web 內容。這些訊息由新增到window.chrome.webview.addEventListener
的處理程式捕獲。
通訊機制使用原生功能將訊息從 Web 內容傳遞到宿主程式。
在專案中,當 WebView2 控制元件(通過頁面連結)導航到一個頁面時,它會在位址列中顯示新網頁的 URL 並彈出新網頁的 URL。
- 在
Form1.cs
檔案中,更新建構函式並建立InitializeAsync
函式,程式碼片段如下:
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
webView.NavigationStarting += EnsureHttps;
InitializeAsync();
}
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
}
在InitializeAsync
函式裡,要用EnsureCoreWebView2Async
awaits 呼叫方式,因為CoreWebView2 的初始化是非同步的。
- CoreWebView2 初始化後,註冊一個事件處理方法來響應
WebMessageReceived
事件。在Form1.cs
檔案中,使用以下程式碼替換InitializeAsync
並新增UpdateAddressBar
。
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
webView.CoreWebView2.WebMessageReceived += UpdateAddressBar;
}
void UpdateAddressBar(object sender, CoreWebView2WebMessageReceivedEventArgs args)
{
String uri = args.TryGetWebMessageAsString();
addressBar.Text = uri;
webView.CoreWebView2.PostWebMessageAsString(uri);
}
-
為了讓WebView2傳送和響應web訊息,
CoreWebView2
初始化後,宿主程式在web內容中注入一個指令碼:
a. 使用postMessage
將 URL 傳送到宿主程式。
b. 註冊一個事件處理程式以列印從宿主程式傳送的訊息。 -
在
Form1.cs
檔案中,用以下程式碼段修改InitializeAsync
:
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
webView.CoreWebView2.WebMessageReceived += UpdateAddressBar;
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.postMessage(window.document.URL);");
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.addEventListener(\'message\', event => alert(event.data));");
}
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 當通過頁面連結訪問到新的URI時,WebView2 控制元件便會將新頁面地址顯示到位址列。
至此,一個 WebView2 應用就完成了。
本文將介紹如何在WinForms中嵌入WebView2,並講到WebView2的主要特徵。點選瞭解更多WebView2的API。
1. 準備
- Visual Studio 2017 及以上版本
- WebView2執行時,或者安裝Beta,Dev,Canary任一版本的 Microsoft Edge 預覽版。受支援的作業系統有:Windows 11\10\8.1\7
- 推薦使用82.0.488.0以上的Canary(日更)版本。
2. 建立單窗體應用
創那一個只包括主窗體的桌面專案:
- 開啟Visual Studio
- 依次點 檔案->新建->工程
- 點 建立新的工程
- 選擇 C# Windows Forms App (.NET Framework) ,然後點 Next
- 輸入 工程名稱 和 位置 ,在 Framework下拉列表中,選擇 ** .NET Framework 4.7.2** 或以上版本
- 點 建立
3. 安裝 WebView2 SDK
使用 NuGet 為工程新增 WebView2 SDK
- 在 Solution Explorer 右鍵點選工程名,在彈出選單中選擇 Manage NuGet Packages
- 點 Browse
- 選擇 Include prerelease(包含預覽版)
- 在查詢框中,輸入WebView2,在結果中選擇 Microsoft.Web.WebView2
- 選擇預設版本並點 Install
- 點 Ok
- 點 File > Save All (Ctrl+Shift+S) ,儲存工程
- 點 F5 編譯並執行後,程式的執行結果是一個空窗體
4. 建立一個WebView
在你的應用中新增一個WebView2控制元件。
- 點 Project > Add Form (Windows Forms)
- 在 Add New Item 視窗中,依次點 Visual C# Items > Web > Windows Forms > Form (Windows Forms) ,然後點 Add
- 點 View > Toolbox
- 在 Toolbox ,點開 WebView2 Windows Forms Control
注意:如果你用的是Visual Studio 2017,在Toolbox中預設是找不到WebView2控制元件的。若想讓其顯示,則需要依次選 Tools > Options > General 並且將 Automatically Populate Toolbox 設定為 true
- 把 WebView2 控制元件拖到 Form 窗體上。
- 在 Properties 工具框中,將 Name 屬性設定為 webView。可以使用 分類- 按字母排序 來找到需要的屬性
- WebView2的 Source 屬性用於初始化頁面的URI。將其值設定為:https://www.microsoft.com
- 點 File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行工程
- WebView2 控制元件中顯示如下:
注意:如果你的是高解析度顯示器,你需要為窗體應用設定置高解析度支援
5. 新增控制元件及處理窗體resize事件
從Toolbox中新增更多控制元件,並處理窗體的resize事件。
- 點 View > Toolbox
- 在 Toolbox 點 Common Controls
- 把 TextBox 拖動到窗體上
- 在 Properties屬性設定視窗,將Name 屬性設定為 addressBar
- 從 Toolbox 中拖動 Button 控制元件到窗體上
- 在Properties屬性設定視窗,將Name 屬性設定為 goButton
- 將Text屬性設定為 Go!
- 調整Button大小以適應文字
- 將文字框放在Button左側,並與按鈕文字對齊如下
- 重置窗體大小
- 點 View > Code 開啟窗體程式碼檔案。編寫
Form_Resize
函式處理窗體大小改變時,控制元件在恰當的位置。 - 刪除如下程式碼
public Form1()
{
InitializeComponent();
}
- 拷貝如下程式碼到剛刪除的程式碼的相同位置
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
}
private void Form_Resize(object sender, EventArgs e)
{
webView.Size = this.ClientSize - new System.Drawing.Size(webView.Location);
goButton.Left = this.ClientSize.Width - goButton.Width;
addressBar.Width = goButton.Left - addressBar.Left;
}
- 點**File > Save All (Ctrl+Shift+S) **儲存工程
-
F5編譯執行,效果如下:
6. 地址導航
在應用中新增位址列,讓使用者可以通過改變位址列來改變WebView2展示的內容。
- 在
Form1.cs
中新增CoreWebView2
名稱空間,程式碼如下:
using Microsoft.Web.WebView2.Core;
- 在窗體設計介面,雙擊Go按鈕,以在
Form1.cs
中新增goButton_Click
事件響應方法,將以下程式碼拷到方法中:
private void goButton_Click(object sender, EventArgs e)
{
if (webView != null && webView.CoreWebView2 != null)
{
webView.CoreWebView2.Navigate(addressBar.Text);
}
}
這樣,```goButton_Click```方法就實現了當使用者在位址列輸入地址並點選Go按鈕時,WebView2就將顯示址址欄中的地址所代表的頁面內容。
- 點 **File > Save All (Ctrl+Shift+S) **儲存工程
- F5編譯並執行
- 在位址列中輸入你想訪問的地址關點Go,驗證下視窗上顯示的是不是你想要的內容吧。
注意:在位址列中應輸入完整的URL,如果址址不是以http://
或https://
開頭的話,會遇到ArgumentException
異常
7. Navigation(導航) 事件
在頁面跳轉過程中,WebView2控制元件會發起一系列事件。而嵌入WebView2的應用會監聽到以下事件:
- NavigationStarting
- SourceChanged
- ContentLoading
- HistoryChanged
- NavigationCompleted
瞭解更多關於WebView2的導航事件
當一個錯誤發生時,會引發以下事件,可能取決於對錯誤網頁的導航 - SourceChanged
- ContentLoading
- HistoryChanged
以下操作,將為NavigationStarting委託註冊一個處理方法,處理當地址不是Https時,取消頁面請求。通過此例來展示如何使用這些事件。 - 在
Form1.cs
中,做如下程式碼更改,新增一個EnsureHttps
方法
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
webView.NavigationStarting += EnsureHttps;
}
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
if (!uri.StartsWith("https://"))
{
args.Cancel = true;
}
}
在建構函式中,EnsureHttps
被註冊為WebView2控制元件的NavigationStarting
的事件處理方法。
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 如果訪問HTTPS會開啟正常的頁面,如果是HTTP則不會正常訪問
8. 指令碼
主程式可以在執行時向WebView2注入JavaScript指令碼。可以讓WebView2執行任意的JavaScript,或者新增初始化指令碼。注入的JavaScript適用於所有新的頂層文件和任何子框架,直到JavaScript被刪除。注入的 JavaScript 以特定的時間執行。
- 在建立全域性物件後執行注入的JavaScript。
- 在執行HTML文件中包含的任何其他指令碼之前執行注入的JavaScript。
1.例如,在使用者導航到非 HTTPS 站點時,添加發送警報的指令碼。修改EnsureHttps
函式,使用ExecuteScriptAsync
方法將指令碼注入到網頁內容中,如下圖所示
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
if (!uri.StartsWith("https://"))
{
webView.CoreWebView2.ExecuteScriptAsync($"alert('{uri} is not safe, try an https link')");
args.Cancel = true;
}
}
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 應用在訪問非 HTTPS 的網站時顯示警報
9. 宿主程式與頁面之間的通訊
宿主程式和頁面內容可以使用 postMessage
進行通訊如下:
- WebView2 控制元件中的 Web 內容可以使用
window.chrome.webview.postMessage
向宿主程式釋出訊息。宿主程式使用任何註冊到WebMessageReceived
委託方法處理訊息。 - 主程式使用
CoreWebView2.PostWebMessageAsString
或CoreWebView2.PostWebMessageAsJSON
將訊息釋出到 WebView2 控制元件中的 Web 內容。這些訊息由新增到window.chrome.webview.addEventListener
的處理程式捕獲。
通訊機制使用原生功能將訊息從 Web 內容傳遞到宿主程式。
在專案中,當 WebView2 控制元件(通過頁面連結)導航到一個頁面時,它會在位址列中顯示新網頁的 URL 並彈出新網頁的 URL。
- 在
Form1.cs
檔案中,更新建構函式並建立InitializeAsync
函式,程式碼片段如下:
public Form1()
{
InitializeComponent();
this.Resize += new System.EventHandler(this.Form_Resize);
webView.NavigationStarting += EnsureHttps;
InitializeAsync();
}
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
}
在InitializeAsync
函式裡,要用EnsureCoreWebView2Async
awaits 呼叫方式,因為CoreWebView2 的初始化是非同步的。
- CoreWebView2 初始化後,註冊一個事件處理方法來響應
WebMessageReceived
事件。在Form1.cs
檔案中,使用以下程式碼替換InitializeAsync
並新增UpdateAddressBar
。
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
webView.CoreWebView2.WebMessageReceived += UpdateAddressBar;
}
void UpdateAddressBar(object sender, CoreWebView2WebMessageReceivedEventArgs args)
{
String uri = args.TryGetWebMessageAsString();
addressBar.Text = uri;
webView.CoreWebView2.PostWebMessageAsString(uri);
}
-
為了讓WebView2傳送和響應web訊息,
CoreWebView2
初始化後,宿主程式在web內容中注入一個指令碼:
a. 使用postMessage
將 URL 傳送到宿主程式。
b. 註冊一個事件處理程式以列印從宿主程式傳送的訊息。 -
在
Form1.cs
檔案中,用以下程式碼段修改InitializeAsync
:
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async(null);
webView.CoreWebView2.WebMessageReceived += UpdateAddressBar;
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.postMessage(window.document.URL);");
await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.chrome.webview.addEventListener(\'message\', event => alert(event.data));");
}
- File > Save All (Ctrl+Shift+S) 儲存工程
- F5 編譯執行
- 當通過頁面連結訪問到新的URI時,WebView2 控制元件便會將新頁面地址顯示到位址列。
至此,一個 WebView2 應用就完成了。