当在 WebView2 控件上右键单击时,如何覆盖出现的 ContextMenu?

9

如何覆盖右键单击 WebView2 控件时出现的 ContextMenu?

当您在 WebView2 控件上右键单击时,将会出现包含“刷新”、“另存为”等选项的标准上下文菜单。

我该如何使自己的 ContextMenuStrip 替代标准上下文菜单,在鼠标右键点击时出现?

3个回答

12

更新(现在该代码将在右键单击时显示您的上下文菜单,并在单击任何地方时隐藏它):

您可以注入以下javascript到您的网页中(它订阅了'contextmenu'事件和'mousedown'事件):

document.addEventListener('contextmenu', function (event)
{
    let jsonObject =
    {
        Key: 'contextmenu',
        Value:
        {
            X: event.screenX,
            Y: event.screenY
        }
    };
    window.chrome.webview.postMessage(jsonObject);
});

document.addEventListener('mousedown', function (event)
{
    let jsonObject =
    {
        Key: 'mousedown',
        Value:
        {
            X: event.screenX,
            Y: event.screenY
        }
    };
    window.chrome.webview.postMessage(jsonObject);
});

最简单的方法是将它保存在一个文件中(我称之为 'Javascript1.js')。

要使用 'CoreWebView2' 实例,必须初始化 WebView2 控件,并订阅 'CoreWebView2InitializationCompleted' 事件来解决此问题。

要注入 JavaScript,可以从文件中加载它,并使用 AddScriptToExecuteOnDocumentCreatedAsync 来注入它。

您需要禁用默认上下文菜单。这可以通过将 AreDefaultContextMenusEnabled 属性设置为 false 来完成。

然后,您需要订阅 WebMessageReceived 事件并处理两个事件。为此,请创建一个带有“Key”和“Value”的结构,以反序列化从 JavaScript 代码发送的 JSON 字符串。

C# 代码 显示整个窗体及其事件:

using Newtonsoft.Json;
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        struct JsonObject
        {
            public string Key {get; set;}
            public PointF Value{get; set;}

        private async void WebView21_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
        {
            webView21.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
            string script = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, @"Javascript1.js"));
            await webView21.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(script);
        }

        private void WebView21_WebMessageReceived(object sender, Microsoft.Web.WebView2.Core.CoreWebView2WebMessageReceivedEventArgs e)
        {
            JsonObject jsonObject = JsonDeserializer.Deserialize<JsonObject>(e.WebMessageAsJson);
            switch (jsonObject.Key)
            {
                case "contextmenu":
                    contextMenuStrip1.Show(Point.Truncate(jsonObject.Value));
                    break;
                case "mousedown":
                    contextMenuStrip1.Hide();
                    break;
            }
        }
    }
}

高级版本可以在此处找到:覆盖Webview2上下文菜单以及默认菜单


这个可以工作,但还需要一些方法来关闭菜单,否则如果你除了选择菜单项之外做任何事情,它就会一直停留在那里。 - Garr Godfrey
2
@GarrGodfrey:我已更新答案,加入了隐藏上下文菜单的代码。 - Poul Bak
不过,其中一个缺点是每次鼠标点击时都会首先触发此事件并解析Json。目前我还没有找到解决方法。 - Dave
1
@Dave:鼠标点击并不需要电脑太多的资源,JSON解析也是一样,所以不用担心性能问题。顺便说一下,我刚刚更改了代码,使用了“CoreWebView2InitializationCompleted”事件和等待“AddScriptToExecuteOnDocumentCreatedAsync”函数。 - Poul Bak
1
你可以添加 event.preventDefault() - Perry
显示剩余3条评论

6
我们目前还没有完全支持自定义上下文菜单,但我们有一个功能请求跟踪。在此期间,您可以使用该功能请求问题中描述的解决方法来解决此问题。
基本上,解决方法是使用document.body的contextmenu事件来拦截通常的上下文菜单处理并实现您自己的菜单。您可以使用window.chrome.webview.postMessage将上下文菜单事件发送到您的本机代码以创建本机上下文菜单,或者您可以使用HTML / JS实现上下文菜单。
很抱歉这不是一个简单的解决方案。如果您愿意,您可以在功能请求中添加自己的评论,让我们了解您在WebView2中使用上下文菜单的情况等。谢谢!

0
显然,David Risney所提到的功能请求("一个跟踪该功能请求的链接")现在已经关闭。
这篇完整的learn.microsoft文章展示了如何自定义它(添加自定义项,删除其他项...)https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/context-menus?tabs=csharp 此外,属性AreDefaultContextMenusEnabled现在可以简单地禁用它。https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/context-menus?tabs=csharp#disabling-context-menus 例如,在CoreWebView2InitializationCompleted事件中:
private void WebView2_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
    WebView2.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接