支援平台:Win32、Windows Forms、WinUI、WPF。
WebView2 控制項基於 COM) (元件物件模型 ,必須在 單一執行緒公寓 (STA) 執行緒上執行。
執行緒安全性
WebView2 必須建立在使用 message pump 的 UI 執行緒上。 所有回調都發生在該執行緒上,且對 WebView2 的請求必須在該執行緒上完成。 使用其他討論串的 WebView2 並不安全。
唯一的例外是 Content 的 CoreWebView2WebResourceRequest性質。
Content屬性串流是從背景執行緒讀取的。 串流應該是敏捷的,或是從背景 STA 建立,以防止 UI 執行緒的效能下降。
物件屬性為單執行緒。 例如,從非Main執行緒呼叫CoreWebView2CookieManager.GetCookiesAsync(null)會成功, (Cookie 會被回傳) ;然而,若在呼叫後嘗試存取 Cookie 的屬性 (,如 c.Domain) ,則會拋出例外。
重新入選
回調,包括事件處理程序和完成處理程序,都是串行執行。 在執行事件處理器並開始訊息迴圈後,事件處理程序或完成回調無法以重入方式執行。 如果 WebView2 應用程式嘗試在 WebView2 事件處理程序中同步建立巢狀訊息迴圈或模態介面,這種做法會導致嘗試重新進入。 WebView2 不支援這種重入機制,會讓事件處理器無限期地留在堆疊中。
例如,以下編碼方法不被支援:
private void Btn_Click(object sender, EventArgs e)
{
// Post web message when button is clicked
this.webView2Control.ExecuteScriptAsync("window.chrome.webview.postMessage(\"Open Dialog\");");
}
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
string msg = e.TryGetWebMessageAsString();
if (msg == "Open Dialog")
{
Form1 form = new Form1(); // Create a new form that contains a new WebView2 instance when web message is received.
form.ShowDialog(); // This will cause a reentrancy issue and cause the newly created WebView2 control inside the modal dialog to hang.
}
}
相反地,請排程在事件處理程序完成後進行適當的工作,如下程式碼所示:
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
string msg = e.TryGetWebMessageAsString();
if (msg == "Open Dialog")
{
// Show a modal dialog after the current event handler is completed, to avoid potential reentrancy caused by running a nested message loop in the WebView2 event handler.
System.Threading.SynchronizationContext.Current.Post((_) => {
Form1 form = new Form1();
form.ShowDialog();
form.Closed();
}, null);
}
}
注意事項
對於 WinForms 和 WPF 應用程式,若要取得完整的調解堆疊以便除錯,必須啟用 WebView2 應用程式的原生程式碼除錯,具體如下:
- 在 Visual Studio 開啟你的 WebView2 專案。
- 在解決方案方案總管中,右鍵點擊 WebView2 專案,然後選擇屬性。
- 選擇 除錯 標籤,然後如下所示選擇 啟用原生程式碼除錯 勾選框。
延期
部分 WebView2 事件會讀取相關事件參數上的值,或在事件處理程序完成後啟動某些動作。 如果你也需要執行非同步操作,例如事件處理程序,請對相關事件的事件參數使用該 GetDeferral 方法。 回傳Deferral物件確保事件處理器在請求該方法Deferral之前Complete不會被視為完整。
例如,你可以利用事件 NewWindowRequested 在事件處理程序完成時,作為子視窗提供 CoreWebView2 to connect 視窗。 但如果你需要非同步建立 ,CoreWebView2你應該呼叫 GetDeferral 該方法。NewWindowRequestedEventArgs 在你非同步建立CoreWebView2並設定NewWindowRequestedEventArgsNewWindow屬性後,CompleteDeferral呼叫該方法回傳GetDeferral的物件。
C 語言中的延後#
在 C# 中使用 a Deferral 時,最佳做法是搭配 using 區塊一起使用。
using封鎖確保即使中間拋using出例外,也能完成該任務Deferral。 如果你有程式碼可以明確呼叫 Complete,但在呼叫 Complete 發生前拋出例外,那麼延遲直到垃圾回收器最終收回並處理遞延處理時才會完成。 在此期間,WebView2 會等待應用程式程式碼處理事件。
例如,不要做以下操作,因為如果呼叫前CompleteWebResourceRequested有例外,該事件就不被視為「處理」,會阻擋 WebView2 渲染該網頁內容。
private async void WebView2WebResourceRequestedHandler(CoreWebView2 sender,
CoreWebView2WebResourceRequestedEventArgs eventArgs)
{
var deferral = eventArgs.GetDeferral();
args.Response = await CreateResponse(eventArgs);
// Calling Complete is not recommended, because if CreateResponse
// throws an exception, the deferral isn't completed.
deferral.Complete();
}
相反地,請使用 using 方塊,如以下範例所示。
using區塊確保任務Deferral完成,不論是否有例外。
private async void WebView2WebResourceRequestedHandler(CoreWebView2 sender,
CoreWebView2WebResourceRequestedEventArgs eventArgs)
{
// The using block ensures that the deferral is completed, regardless of
// whether there's an exception.
using (eventArgs.GetDeferral())
{
args.Response = await CreateResponse(eventArgs);
}
}
封鎖 UI 執行緒
WebView2 依賴 UI 執行緒的訊息泵來執行事件處理回調與非同步方法補全回調。 如果你使用阻擋訊息泵的方法,例如 Task.Result 或 WaitForSingleObject,那麼你的 WebView2 事件處理器和非同步方法完成處理器就不會執行。 例如,以下程式碼未完成,因為 Task.Result 在等待 ExecuteScriptAsync 完成時停止訊息泵。 因為訊息泵被阻塞, ExecuteScriptAsync 無法完成。
例如,以下程式碼無法運作,因為它使用 Task.Result了 。
private void Button_Click(object sender, EventArgs e)
{
string result = webView2Control.CoreWebView2.ExecuteScriptAsync("'test'").Result;
MessageBox.Show(this, result, "Script Result");
}
相反地,請使用非同步 await 機制,如 async 和 await,這樣不會阻擋訊息泵或使用者介面執行緒。 例如:
private async void Button_Click(object sender, EventArgs e)
{
string result = await webView2Control.CoreWebView2.ExecuteScriptAsync("'test'");
MessageBox.Show(this, result, "Script Result");
}
另請參閱
- 開始使用 WebView2
- WebView2Samples 儲存庫 ——WebView2 功能的完整範例。
- WebView2 API 參考