.NET混合開發解決方案9 WebView2控制元件的導航事件

張傳寧發表於2022-05-07

WebView2控制元件應用詳解系列部落格

.NET桌面程式整合Web網頁開發的十種解決方案 

.NET混合開發解決方案1 WebView2簡介

.NET混合開發解決方案2 WebView2與Edge瀏覽器的區別

.NET混合開發解決方案3 WebView2的程式模型

.NET混合開發解決方案4 WebView2的執行緒模型

.NET混合開發解決方案5 WebView2執行時與分發應用

.NET混合開發解決方案7 WinForm程式中通過NuGet管理器引用整合WebView2控制元件

.NET混合開發解決方案8 WinForm程式中通過設定固定版本執行時的BrowserExecutableFolder屬性整合WebView2控制元件

  在我的部落格《.NET混合開發解決方案7 WinForm程式中整合WebView2》中介紹了WinForm程式中整合WebView2元件的詳細步驟以及注意事項。這只是最基本的應用,WebView2功能之所以強大,是因為它提供了很多開放的屬性與事件供開發者呼叫以完成複雜的功能。具體可以參考我的部落格《.NET混合開發解決方案2 WebView2與Edge瀏覽器的區別》

  本文介紹WebView2應用程式的導航事件。當WebView2例項中顯示的內容發生特定的非同步操作時,導航事件會執行。例如,當WebView2使用者導航到新網站時,本機內容(WinForm、WPF、Win32、WinUI)通過偵聽 NavigationStarting 事件來偵聽更改。導航操作完成後,NavigationCompleted 事件將執行。

導航事件的正常順序為:

  1. NavigationStarting
  2. SourceChanged
  3. ContentLoading
  4. HistoryChanged
  5. BasicAuthenticationRequested
  6. DOMContentLoaded
  7. NavigationCompleted

以下事件描述每次導航操作期間 WebView2 的狀態:

上圖顯示了在各自的事件引數上具有相同NavigationId屬性的導航事件。

  • 使用導航ID(在NavigationId事件中提供)跟蹤每個新文件的導航事件。每次成功導航到新文件時,WebView2的NavigationId事件都會發生更改。
  • 具有不同NavigationId事件例項的導航事件可能會重疊。例如,啟動導航事件時,必須等待相關的NavigationStarting事件。如果隨後啟動另一個導航,您將看到以下序列:
    1. 第一次導航的 NavigationStarting 事件。
    2. 第二次導航的 NavigationStarting 事件。
    3. 第一次導航的 NavigationCompleted 事件。
    4. 第二次導航的所有其他相應導航事件。
  • 在錯誤情況下,可能有或可能沒有內容載入事件,這取決於導航是否繼續導航到錯誤頁面。
  • 如果發生HTTP重定向,則一行中有多個NavigationStarting事件,其中後面的事件引數設定了IsRedirect屬性;但是,NavigationId事件保持不變。
  • 相同的文件導航事件(例如導航到同一文件中的片段)不會導致NavigationStarting事件,也不會增加NavigationId事件。
  • 要監視或取消WebView2例項中子框架內的導航事件,請使用FrameNavigationStarting和FrameNavigationCompleted事件。這些事件的行為類似於等效的非框架對應事件。

當在文字框中輸入目標網址後,點選【導航】按鈕,具體執行邏輯如下

發生錯誤時,會引發以下事件,這可能取決於對錯誤網頁的導航:

  • SourceChanged
  • ContentLoading
  • HistoryChanged

如果發生HTTP重定向,則一行中有多個NavigationStarting事件。

示例演示

先看一個效果動畫

邏輯程式碼

  1 public partial class Frm2Navigation : Form
  2 {
  3     public Frm2Navigation()
  4     {
  5         InitializeComponent();
  6 
  7         InitializeAsync();
  8 
  9         webView2.CoreWebView2InitializationCompleted += WebView2_CoreWebView2InitializationCompleted;
 10 
 11         webView2.NavigationStarting += WebView2_NavigationStarting;
 12         webView2.NavigationCompleted += WebView2_NavigationCompleted;
 13     }
 14 
 15     async void InitializeAsync()
 16     {
 17         await webView2.EnsureCoreWebView2Async(null);
 18     }
 19 
 20     private void WebView2_CoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
 21     {
 22         if (e.IsSuccess == false)
 23         {
 24             MessageBox.Show("WebView2_CoreWebView2InitializationCompleted 事件,發生異常。"
 25                           + Environment.NewLine + e.InitializationException.Message,
 26                             "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
 27         }
 28 
 29         webView2.SourceChanged += WebView2_SourceChanged;
 30         webView2.ContentLoading += WebView2_ContentLoading;
 31         webView2.CoreWebView2.HistoryChanged += CoreWebView2_HistoryChanged;
 32         webView2.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
 33 
 34         webView2.CoreWebView2.BasicAuthenticationRequested += CoreWebView2_BasicAuthenticationRequested;
 35         webView2.CoreWebView2.ProcessFailed += CoreWebView2_ProcessFailed;
 36     }
 37 
 38     private void WebView2_NavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e)
 39     {
 40         string uri = e.Uri;
 41         if (!uri.StartsWith("https://"))
 42         {
 43             //webView2.CoreWebView2.ExecuteScriptAsync($"alert('{uri} 不安全, 請嘗試https連結。')");
 44 
 45             DialogResult dr = MessageBox.Show($"{uri} 不安全, 請嘗試https連結。\r\n\r\n 確定要訪問嗎?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
 46             if (dr == DialogResult.Cancel)
 47             {
 48                 e.Cancel = true;
 49             }
 50         }
 51     }
 52 
 53     private void WebView2_SourceChanged(object? sender, CoreWebView2SourceChangedEventArgs e)
 54     {
 55         //if(e.IsNewDocument)
 56         //{
 57         // webView2.CoreWebView2.ExecuteScriptAsync("alert('WebView2_SourceChanged事件。= e.IsNewDocument = true')");
 58         //}
 59 
 60         MessageBox.Show("WebView2_SourceChanged 事件。"
 61                       + Environment.NewLine + "e.IsNewDocument = " + e.IsNewDocument,
 62                         "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
 63     }
 64 
 65     private void WebView2_ContentLoading(object? sender, CoreWebView2ContentLoadingEventArgs e)
 66     {
 67         //webView2.CoreWebView2.ExecuteScriptAsync("alert('WebView2_SourceChanged事件。= e.IsNewDocument = true')");
 68 
 69         MessageBox.Show("WebView2_ContentLoading 事件。"
 70                       + Environment.NewLine + "e.IsErrorPage = " + e.IsErrorPage,
 71                         "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
 72     }
 73 
 74     private void CoreWebView2_HistoryChanged(object? sender, object e)
 75     {
 76         MessageBox.Show("CoreWebView2_HistoryChanged 事件。",
 77                         "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
 78     }
 79 
 80     private void CoreWebView2_DOMContentLoaded(object? sender, CoreWebView2DOMContentLoadedEventArgs e)
 81     {
 82         MessageBox.Show("CoreWebView2_DOMContentLoaded 事件。"
 83                       + Environment.NewLine + "e.NavigationId = " + e.NavigationId,
 84                         "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
 85     }
 86 
 87     private void WebView2_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
 88     {
 89         MessageBox.Show("WebView2_NavigationCompleted 事件。"
 90                       + Environment.NewLine + "e.NavigationId = " + e.NavigationId
 91                       + Environment.NewLine + "e.IsSuccess = " + e.IsSuccess
 92                       + Environment.NewLine + "e.WebErrorStatus = " + e.WebErrorStatus,
 93                       "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
 94     }
 95 
 96 
 97     private void CoreWebView2_ProcessFailed(object? sender, CoreWebView2ProcessFailedEventArgs e)
 98     {
 99         MessageBox.Show("CoreWebView2_ProcessFailed 事件。"
100                       + Environment.NewLine + "e.ExitCode = " + e.ExitCode
101                       + Environment.NewLine + "e.FrameInfosForFailedProcess = " + e.FrameInfosForFailedProcess
102                       + Environment.NewLine + "e.ProcessDescription = " + e.ProcessDescription
103                       + Environment.NewLine + "e.ProcessFailedKind = " + e.ProcessFailedKind
104                       + Environment.NewLine + "e.Reason = " + e.Reason,
105                       "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
106     }
107 
108 
109     private void CoreWebView2_BasicAuthenticationRequested(object? sender, CoreWebView2BasicAuthenticationRequestedEventArgs e)
110     {
111         MessageBox.Show("CoreWebView2_BasicAuthenticationRequested 事件。"
112                       + Environment.NewLine + "e.Uri = " + e.Uri
113                       + Environment.NewLine + "e.Cancel = " + e.Cancel
114                       + Environment.NewLine + "e.Challenge = " + e.Challenge
115                       + Environment.NewLine + "e.Response = " + e.Response,
116                         "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
117 
118     }
119 
120 
121     // 訪問url
122     private void btnGo_Click(object sender, EventArgs e)
123     {
124         string rawUrl = txtUrl.Text;
125         if (string.IsNullOrWhiteSpace(rawUrl))
126         {
127             MessageBox.Show("請輸入網址。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
128 
129             txtUrl.Focus();
130 
131             return;
132         }
133 
134         Uri uri;
135 
136         if (Uri.IsWellFormedUriString(rawUrl, UriKind.Absolute))
137         {
138             uri = new Uri(rawUrl);
139         }
140         else if (rawUrl.Contains(" ") == false && rawUrl.Contains(".") == false)
141         {
142             // 無效的URI包含一個點且沒有空格,請嘗試在前面新增http://標記
143             uri = new Uri("http://" + rawUrl);
144         }
145         else if (rawUrl.StartsWith("http://") == false)
146         {
147             uri = new Uri("http://" + rawUrl);
148         }
149         else
150         {
151             // 其他情況將其視為網路搜尋
152             uri = new Uri("https://bing.com/search?q=" + string.Join("+", Uri.EscapeDataString(rawUrl).Split(new string[] { "%20" }, StringSplitOptions.RemoveEmptyEntries)));
153         }
154 
155         //webView2.CoreWebView2.Navigate(url.Trim());
156         webView2.Source = uri;
157     }
158 }

注意事項

CoreWebview2的相關事件必須在它的 CoreWebView2InitializationCompleted 事件(CoreWebView2物件初始化完成後事件)裡面註冊

  • webView2.CoreWebView2.HistoryChanged
  • webView2.CoreWebView2.DOMContentLoaded
  • webView2.CoreWebView2.BasicAuthenticationRequested
  • webView2.CoreWebView2.ProcessFailed

如上第31、32、34、35行。

相關文章