.NET混合開發解決方案13 自定義WebView2中的上下文菜單

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混合開發解決方案9 WebView2控件的導航事件

.NET混合開發解決方案10 WebView2控件調用網頁JS方法

.NET混合開發解決方案11 網頁JS調用C#方法

.NET混合開發解決方案12 網頁JS調用C#方法訪問WinForm或WPF窗體

Edge瀏覽器中的網頁,點擊鼠標右鍵,出現上下文菜單及子菜單,如下圖

WebView2控件加載網頁後,鼠標在網頁上點擊右鍵,也會出現上下文菜單,如下圖

對比可以看出WebView2控件中的右鍵上下文菜單內容比Edge瀏覽器中網頁的右鍵右鍵上下文菜單的數量少。結合我的博客《.NET混合開發解決方案2 WebView2與Edge瀏覽器的區別》可知,WebView2控件中對於網頁右鍵上下文菜單做了裁剪。

在企業級應用軟件開發中,可能有以下幾種種常有且實用的需求

1、禁用網頁右鍵菜單

使用 webView2.CoreWebView2.ExecuteScriptAsync() 方法執行JS腳本即可實現禁用右鍵菜單

await webView.CoreWebView2.ExecuteScriptAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");

或者通過C#編碼禁用右鍵菜單

 webView2.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;

有的開發者小夥伴會說,我在網頁中寫JS也可以禁用右鍵上菜單,確實如此

function document.oncontextmenu()
{
   return false;
}
 
 
function nocontextmenu()
{
  if(document.all) {
     event.cancelBubble=true;
     event.returnvalue=false;
     return false;
   }
}

但是通過WebView2進行控制,一方面不改變網頁本身的功能,另一方面可以統一控制網頁右鍵菜單的啓用與禁用。

2、從默認上下文菜單中刪除菜單項

  通過WebView2能禁用右鍵菜單,理論上也可以自定義右鍵菜單。WebView2提供了豐富的API供開發者使用,參考微軟官方文檔《自定義 WebView2 中的上下文菜單》,可以實現自定義的右鍵菜單。

關於右鍵菜單的術語

  • 菜單項  包括複選框、命令、單選按鈕、分隔符和子菜單。
  • 命令  五種類型的菜單項之一。
  • 上下文菜單 屬於 WebView2 控件的默認上下文菜單 (右鍵單擊菜單) 或自定義上下文菜單 (右鍵單擊菜單) 屬於主機應用。

與WebView2控件右鍵菜單相關的事件、類、屬性與枚舉

  指示爲目標屬性創建上下文菜單的上下文種類。此枚舉將始終表示導致上下文菜單請求的活動元素。例如,如果有一個包含多個圖像、音頻和文本的選擇,最終用戶在此選擇中右鍵單擊的元素將是此枚舉表示的選項。

    • Audio  指示上下文菜單是爲音頻元素創建的。
    • Image 指示上下文菜單是爲圖像元素創建的。
    • Page 指示上下文菜單是爲頁面創建的,沒有任何其他內容。
    • SelectedText 指示上下文菜單是爲所選文本創建的。
    • Video 指示上下文菜單是爲視頻元素創建的。

首先獲取WebView2控件的默認右鍵菜單列表,查看每一項的具體屬性信息。通過註冊WebView2的ContextMenuRequested事件,使用事件參數CoreWebView2ContextMenuRequestedEventArgs中提供的數據來顯示包含所選條目的自定義上下文菜單。

默認提供12個右鍵菜單項(包含分隔符),調試代碼查看每個菜單項信息,如下

觀察12個菜單項,可以發現以下規律

  • 分割線的Kind值爲Separator,其餘菜單項的Kind值爲Command。
  • 分割線的CommandId值爲-1,label值爲空字符串,name值爲other。
  • Kind值爲Command的菜單項CommandId、label、name值不同且唯一。

一般的應用程序保留【返回】、【前進】、【刷新】三個菜單項即可滿足。此時就需要刪除其他的菜單項。實現邏輯如下

 1 private void CoreWebView2_ContextMenuRequested(object? sender, CoreWebView2ContextMenuRequestedEventArgs args)
 2 {
 3     IList<CoreWebView2ContextMenuItem> allMenuList = args.MenuItems;
 4 
 5     var itemOfSaveAs = allMenuList.FirstOrDefault(x => x.Name == "saveAs");
 6     if (itemOfSaveAs != null)
 7         allMenuList.Remove(itemOfSaveAs);
 8 
 9     var itemOfPrint = allMenuList.FirstOrDefault(x => x.Name == "print");
10     if (itemOfPrint != null)
11         allMenuList.Remove(itemOfPrint);
12 
13     var itemOfCreateQRCode = allMenuList.FirstOrDefault(x => x.Label == "爲此頁面創建 QR 代碼");
14     if (itemOfCreateQRCode != null)
15         allMenuList.Remove(itemOfCreateQRCode);
16 
17     var itemOfShare = allMenuList.FirstOrDefault(x => x.CommandId == 50460);
18     if (itemOfShare != null)
19         allMenuList.Remove(itemOfShare);
20 
21     var itemOfSaveInspectElement = allMenuList.FirstOrDefault(x => x.Name == "inspectElement");
22     if (itemOfSaveInspectElement != null)
23         allMenuList.Remove(itemOfSaveInspectElement);
24 }

測試效果如下圖

現在只有【返回】、【前進】、【刷新】菜單項了,但是最後還有一條分割線。

調試代碼可知目前還有7個菜單項,其中第4,5,6,7項都是分割線。在12個原始菜單項中就包含有四個分割線,所以此處需要刪除這4個分割線

修改邏輯代碼

再次測試,效果如下圖

如果是清空所有的菜單項就比較簡單了,直接清空右鍵菜單列表

IList<CoreWebView2ContextMenuItem> allMenuList = args.MenuItems;
allMenuList.Clear();//清空所有的默認菜單項
3、自定義 WebView2 中的上下文菜單

上述第二個場景中保留了【返回】、【前進】、【刷新】三個菜單項,滿足大多數場景的需求。考慮一些極端情況,系統需要統一實現自定義的右鍵菜單功能。

通過一個簡單的示例來演示如何實現自定義WebView2 中的上下文菜單。

場景:在第二個場景的基礎之上,增加2個自定義右鍵菜單項。

先看下實現效果

同樣需要在WebView2控件的ContextMenuRequested事件中實現

private void CoreWebView2_ContextMenuRequested(object? sender, CoreWebView2ContextMenuRequestedEventArgs args)
{
   IList<CoreWebView2ContextMenuItem> allMenuList = args.MenuItems;

   PopulateContextMenu(args, allMenuList);
}

其中添加菜單項的邏輯如下

CoreWebView2ContextMenuItem 類不能直接實例化,需要使用 webView2.CoreWebView2.Environment.CreateContextMenuItem() 類創建一個菜單對象。CreateContextMenuItem() 方法中傳遞三個參數

1、菜單項的名稱。如果是分割線,則設置爲空字符串。

2、菜單項的圖標,是文件流對象。如果不設置,則賦值爲null。

3、菜單項的類型,包含Command(命令按鈕)、CheckBox(複選框)、Radio(單選框)、Separator(分割線)、Submenu(子菜單)。

程序中我設置了CheckBox,但是運行後沒有生效,暫時不知道什麼原因。如有小夥伴研究出來了,可以分享一下。

菜單項還有Label、CommandId屬性,但是隻讀,無法賦值

調試程序可以看到,創建菜單時,CommandId的值是自動分配的,Label的值與Name相同。

用戶何時請求上下文菜單
當用戶請求打開上下文菜單 ((例如右鍵單擊) )時,應用需要偵聽 ContextMenuRequested 事件。當應用檢測到此事件時,應用應執行以下操作的一些組合:將自定義菜單項添加到默認上下文菜單。
  • 從默認上下文菜單中刪除自定義菜單項。
  • 打開自定義上下文菜單。

該 ContextMenuRequested 事件指示用戶請求打開上下文菜單。

WebView2 控件引發此事件,指示用戶請求在 WebView2 控件中打開上下文菜單,例如右鍵單擊。

僅當前網頁允許顯示上下文菜單時,WebView2 控件纔會引發 ContextMenuRequested 事件,即 AreDefaultContextMenusEnabled true 時引發該事件。

CoreWebView2ContextMenuRequestedEventArgs 包含以下信息:

  • 要填充自定義上下文菜單的 ContextMenuItem 對象的有序列表。 已排序列表包括以下內容:

    • 菜單項的內部名稱。
    • 菜單項的 UI 標籤,顯示給 UI 中的用戶。
    • 菜單項的類型。
    • 鍵盤快捷方式說明(如有 Alt+C)。
    • 自定義菜單項的任何其他屬性。
  • 請求上下文菜單的座標,以便應用可以檢測用戶右鍵單擊的 UI 項。 座標是根據 WebView2 控件的左上角定義的。

  • 包含所選上下文類型的選擇對象 和相應的上下文菜單參數數據。

當用戶在上下文菜單上選擇自定義菜單項時,WebView2 控件將觸發 CustomItemSelected 事件,開發者在該事件中可以自定義業務邏輯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章