8

How do you override the ContextMenu that appears when right clicking on WebView2 Control?

When you right click on WebView2 control, the standard context menu with options such as "Refresh", "Save as", etc. appears.

How do I make my own ContextMenuStrip appear instead that can appear during Right mouse button click ?

Poul Bak
  • 10,450
  • 5
  • 32
  • 57
DotNetSpartan
  • 931
  • 4
  • 20
  • 41

3 Answers3

11

Update (now the code shows your context menu on right click and hides it when you click anywhere):

You can inject the following javascript into your webpage (it subscribes to the 'contextmenu' event and the 'mousedown' event):

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);
});

It's easiest to save it in a file (I call it 'Javascript1.js').

To work with the 'CoreWebView2' instance, the WebView2 control must be initialized, subscribing to 'CoreWebView2InitializationCompleted' solves that.

To inject your javascript, you can load it from the file and use AddScriptToExecuteOnDocumentCreatedAsync to inject it.

You need to disable default context menu. This is done by setting AreDefaultContextMenusEnabled property to false.

Then you need to subscribe to the WebMessageReceived event and handle the two events. To do that, create a structure with a 'Key' and a 'Value' to deserialize the JSON string sent from javascript code.

C# code that shows the whole form with events:

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;
            }
        }
    }
}

The advanced version of this can be found here: Overriding Webview2 context menu along with default one

Poul Bak
  • 10,450
  • 5
  • 32
  • 57
  • this works, although also need some way to dismiss the menu, otherwise it just stays there if you do anything except select a menu item – Garr Godfrey Aug 20 '20 at 06:37
  • 2
    @GarrGodfrey: I have updated the answer to include the code, that hides the context menu. – Poul Bak Aug 20 '20 at 21:58
  • Nice. I also found I can capture the mouse while menu is up and handle the mouse event directly – Garr Godfrey Aug 21 '20 at 04:24
  • One down side though is this event firsts and parses that Json on every mouse click. I haven't found a way around that currently – Dave Mar 04 '21 at 12:40
  • 1
    @Dave: A mouse click does not require much of the computer, neither does the json parsing, so don't worry about performance. BTW, I have just changed the code to use `CoreWebView2InitializationCompleted`event and await `AddScriptToExecuteOnDocumentCreatedAsync`. – Poul Bak Mar 04 '21 at 12:44
  • 1
    you can also add event.preventDefault() – Perry Feb 03 '22 at 16:59
  • I'm new to javascript. Just wanted to know if this line (window.chrome.webview) has any dependency on google chrome. I have uninstalled it and tested it. it's working. – Loch Mar 21 '22 at 09:13
  • @Loch: No it only requires `WebView2`. – Poul Bak Mar 21 '22 at 17:57
6

We don't yet have full support for customizing the context menu, however we have a feature request tracking it. In the interim you may be able to work around this using the work around described in that feature request issue.

Essentially the work around is to use the document.body's contextmenu event to intercept the usual context menu handling and implement your own. You can either use window.chrome.webview.postMessage to send the context menu event up to your native code to create a native context menu, or you could implement the context menu in HTML/JS.

Apologies its not a simple solution. If you like you can add your own comments to the feature request to let us know about your scenario and so on for using context menus in WebView2. Thanks!

David Risney
  • 3,886
  • 15
  • 16
0

Apparently, the feature request that David Risney was refering to ("a feature request tracking it") is now closed.

This full learn.microsoft article shows how to customize it (adding custom items, remove others...) https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/context-menus?tabs=csharp

Also, the property AreDefaultContextMenusEnabled now allow to simply disable it. https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/context-menus?tabs=csharp#disabling-context-menus

For example, in the CoreWebView2InitializationCompleted event :

private void WebView2_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
    WebView2.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
}
Vilo
  • 29
  • 7