'WebView2 JS injection returns empty json string
With WebView2 for targeting Windows, I am trying to setup my own context menu. Either by selected text or by underlying element pointed by mouse click.
However, I can't get DOM element by mouse operation or even by byId. I think my JavaScript injection or WebView property setting is something wrong, but not too sure. Can anyone suggest me the resolution?
The version info.
- OS : Windows 10 Pro 21H2 19044.1682
- Visual Studio : Community 2022 17.1.6
- WebView2 : 1.0.1185.39
- Project Property: Target framework=.NET 6.0; Target OS version=10.0.19041.0
Here's the testing code
using Microsoft.Web.WebView2.Core;
namespace WinFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
HTML(@"C:\temp\test.html");
}
public void HTML(string url)
{
webView21.CoreWebView2InitializationCompleted += WebView2Control_CoreWebView2InitializationCompleted;
webView21.Source = new Uri(url);
}
private void WebView2Control_CoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
{
if (!e.IsSuccess)
{
MessageBox.Show($"WebView2 creation failed, with exception : {e.InitializationException}");
return;
}
// subscribe to events we are interested in
webView21.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested; // user clicked right mouse to show context menu
}
private async void CoreWebView2_ContextMenuRequested(object? sender, Microsoft.Web.WebView2.Core.CoreWebView2ContextMenuRequestedEventArgs e)
{
IList<CoreWebView2ContextMenuItem> menuItemList = e.MenuItems;
menuItemList.Clear(); // clear default menu items, like prev, next, property
//GETTING SELECTED TEXT
string text = e.ContextMenuTarget.HasSelection ? e.ContextMenuTarget.SelectionText : ""; // it works
if (string.IsNullOrEmpty(text)) // no text selection, then examine DOM
{
//GET AN UNDERLYING ELEMENT FROM MOUSE POINT
var result = await webView21.CoreWebView2.ExecuteScriptAsync($"document.elementFromPoint({e.Location.X},{e.Location.Y})"); //it doesn't work, just returns an empty JSON text (not null)
//var result = await webView21.CoreWebView2.ExecuteScriptAsync("function foo(){return 'foo() gets called';}; foo();"); //for testing purpose, it works
//var result = await webView21.CoreWebView2.ExecuteScriptAsync("function foo(){return document.getElementById('table-content'};foo();)"); //it returns an empty result
}
// TO DO
// setup menuItem tree based on the result we got
//......
//......
e.Handled = true;
}
}
}
Solution 1:[1]
I think i managed it, thanks for insights given. My original intent was to capture innerText and href and to feed them to C# code(host). one note. getter/setter has to be ready. Here's complete test code.
using Microsoft.Web.WebView2.Core;
using System.Text.Json;
namespace WinFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
HTML(@"C:\temp\test.html");
}
public void HTML(string url)
{
webView21.CoreWebView2InitializationCompleted += WebView2Control_CoreWebView2InitializationCompleted;
this.webView21.Source = new Uri(url);
}
private void WebView2Control_CoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
{
if (!e.IsSuccess)
{
MessageBox.Show($"WebView2 creation failed, with exception : {e.InitializationException}");
return;
}
// subscribe to events we are interested in
webView21.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested; // user clicked right mouse to show context menu
}
public class HTMLelements
{
public string href { get; set; } = "";
public string innerText { get; set; } = "";
}
private async void CoreWebView2_ContextMenuRequested(object? sender, Microsoft.Web.WebView2.Core.CoreWebView2ContextMenuRequestedEventArgs e)
{
IList<CoreWebView2ContextMenuItem> menuItemList = e.MenuItems;
menuItemList.Clear(); // clear default menu items, like prev, next, property
HTMLelements htmlElements = new(); //Didn't know this new syntax
//GETTING SELECTED TEXT
htmlElements.innerText = e.ContextMenuTarget.HasSelection ? e.ContextMenuTarget.SelectionText : "";
if (string.IsNullOrEmpty(htmlElements.innerText)) // no text selection, then examine DOM
{
//GETTING AN UNDERLYING ELEMENT FROM MOUSE POINT
//it should return JSON string { "href" : "something or empty", "innerText: "something" }
string jScript = $@"
function GetElement() {{
var elem = document.elementFromPoint({ e.Location.X},{ e.Location.Y});
var obj = new Object();
obj.href = elem.href === undefined? '' : elem.href;
obj.innerText = elem.innerText;
return obj;
}};
GetElement();";
var result = await webView21.CoreWebView2.ExecuteScriptAsync(jScript);
htmlElements = JsonSerializer.Deserialize<HTMLelements>(result); // feed them to our class object
}
// TO DO
//setup menuItem tree based on the result we got
//setting up CoreWebView2ContextMenuItem is new to me, hence I use C# standard toolStripMenuItem instead.
//sometime later, I will amend as such
toolStripMenuItemPlaceHolder.Text = htmlElements.innerText;
toolStripMenuItemPlaceHolder.Enabled = true;
if (!string.IsNullOrEmpty(htmlElements.href))
{
toolStripMenuItemPlaceHolder.Tag = htmlElements.href;
toolStripMenuItemShowInBrowser.Enabled = true;
}
else
{
toolStripMenuItemPlaceHolder.Tag = null;
toolStripMenuItemShowInBrowser.Enabled = false;
}
contextMenuStripInBrowser.Show(webView21, e.Location);
e.Handled = false;
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |