'Which WebView2 event/function can be use to replace ScriptNotify Webview event?
Today, I have decided to migrate WebView
control to WebView2
control in a VB.net application.
I have installed WebView2
from NuGet
and I have changed declarations and initialization lines (only 4 lines in my VB program because I'm using 2 WebView2).
When I build my application, Visual Studio 2019
indicates that ScriptNotify
event is not an event of WebView2
!
Private Sub wvSelect_ScriptNotify(
sender As Object,
e As WebViewControlScriptNotifyEventArgs) Handles wvSelect.ScriptNotify
Using old WebView
control, this event is generated using windows.external.notify
Javascript function.
function clickPlus(e) { window.external.notify("+PLUS:"); }
Which event is replacing ScriptNotify
event in WebView2
control?
I'm interested to know the new event and also how this event is called from Javascript.
Solution 1:[1]
A few possible scenarios to handle event notifications with WebView2:
See also: Use JavaScript in WebView for extended scenarios.
Generic initialization:
- The WebView2 instance is named
myWebView2
. - Using basic methods: for example, the JSON deserialization is performed using JavaScriptSerializer. You probably have Json.Net or System.Text.Json instead.
- Also assuming WinForms, you haven't specified the GUI framework
Private Async Sub Load(sender As Object, e as EventArgs) Handles MyBase.Load
await myWebView2.EnsureCoreWebView2Async(Nothing)
End Sub
Also, I'm using this simple class model, used to deserialize the JSON message received, since WebView2.WebMessageReceived assumes a JSON format; you can pass whatever string you want, though.
Private Class JsonEventMessage
Public Property Element As String
Public Property Value As String
End Class
1 - In this scenario, javascript Functions are already defined in the HTML
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function SomeFunction(e, v) {
var json = JSON.stringify({ Element:e.target.id, Value:v });
window.chrome.webview.postMessage(json);
}
</script>
</head>
<body>
<script>
document.getElementById("div1").addEventListener("click", function(e) {SomeFunction(e, '+PLUS:')});
</script>
<div id="div1">Some Text to Click</div>
</body>
</html>
In this case, you just need to subscribe to the WebMessageReceived
event and deserialize the JSON:
AddHandler myWebView2.WebMessageReceived, AddressOf myWebView2_WebMessageReceived
' [...]
Private Sub myWebView2_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
Dim message = New JavaScriptSerializer().Deserialize(Of JsonEventMessage)(e.TryGetWebMessageAsString())
Console.WriteLine(message.Element)
Console.WriteLine(message.Value)
End Sub
Note: I'm using e.TryGetWebMessageAsString() and not e.WebMessageAsJson since the latter is enclosed in quotes (double-stringified). It's better used when you pass a simple string.
2 - Here, a JavaScript Function that can notify a message is defined in HEAD
, but no event handlers are added anywhere else.
Assume you will add HTML Elements at run-time or you don't want to add the event handlers in the HTML or anything else.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function SomeFunction(e, v) {
var json = JSON.stringify({ Element:e.target.id, Value:v });
window.chrome.webview.postMessage(json);
}
</script>
</head>
<body>
<div id="div1">Some Text to Click</div>
</body>
</html>
Subscribe to the WebMessageReceived
event as before and to the NavigationCompleted event. This event is raised when the Document is loaded. We need this event, since, in the example, the event handlers are added to Elements in the Body, which is not available before this point.
In NavigationCompleted
, we can add the JavaScript Function to a string and call the WebView2.ExecuteScriptAsync() method, which executes the script after the DOM is ready, otherwise GetElementById()
would not find the target.
AddHandler myWebView2.WebMessageReceived, AddressOf myWebView2_WebMessageReceived
AddHandler myWebView2.NavigationCompleted, AddressOf myWebView2_NavigationCompleted
' [...]
Private Sub myWebView2_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
Dim message = New JavaScriptSerializer().Deserialize(Of JsonEventMessage)(e.TryGetWebMessageAsString())
' [...]
End Sub
Private Async Sub myWebView2_NavigationCompleted(sender As Object, e As CoreWebView2NavigationCompletedEventArgs)
Dim func As String =
"document.getElementById('div1').
addEventListener('click', function(e) {
SomeFunction(e, '+PLUS:')
});"
Await myWebView2.ExecuteScriptAsync(func)
End Sub
3 - This time, no JavaScript Functions are defined anywhere in the HTML.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="div1">Some Text to Click</div>
</body>
</html>
Case 1:
Subscribe to the WebMessageReceived
and NavigationCompleted
events as before.
In NavigationCompleted
, the JavaScript Function that posts the message is added to the event handler directly. Call ExecuteScriptAsync()
to execute the script and add the Event Listener to a HTML Element.
AddHandler myWebView2.WebMessageReceived, AddressOf myWebView2_WebMessageReceived
AddHandler myWebView2.NavigationCompleted, AddressOf myWebView2_NavigationCompleted
' [...]
Private Sub myWebView2_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
Dim message = New JavaScriptSerializer().Deserialize(Of JsonEventMessage)(e.TryGetWebMessageAsString())
' [...]
End Sub
Private Async Sub myWebView2_NavigationCompleted(sender As Object, e As CoreWebView2NavigationCompletedEventArgs)
Dim func As String =
"document.getElementById('div1').
addEventListener('click', function(e) {
var json = JSON.stringify({Element:e.target.id, Value:'+PLUS:'});
window.chrome.webview.postMessage(json);
});"
Await myWebView2.ExecuteScriptAsync(func)
End Sub
Case 2:
Subscribe to the WebMessageReceived
and WebView2.CoreWebView2InitializationCompleted.
In this case, we're adding an event listener to the Document, then determine which Element has been clicked using the Event.Target
member and any other property or value that can be useful to handle the notification.
Here, I'm simply passing the [Event].target.id
and [Event].target.innerText
as JSON properties. You can of course get any other attribute necessary in your use-case.
AddHandler myWebView2.WebMessageReceived, AddressOf myWebView2_WebMessageReceived
AddHandler myWebView2.CoreWebView2InitializationCompleted, AddressOf myWebView2_CoreWebView2InitializationCompleted
' [...]
Private Sub myWebView2_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs)
Dim message = New JavaScriptSerializer().
Deserialize(Of JsonEventMessage)(e.TryGetWebMessageAsString())
' [...]
End Sub
Private Async Sub myWebView2_CoreWebView2InitializationCompleted(
sender As Object,
e As CoreWebView2InitializationCompletedEventArgs)
Dim func as String =
"document.addEventListener
('click', function(e) {
window.chrome.webview.postMessage(
JSON.stringify({ Element:e.target.id, Value:e.target.innerText })
);
});"
Await myWebView2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(func)
End Sub
Solution 2:[2]
My problem is now solved and my solution is following ...
I want to display following HTML page
<div id="table">
<div id='Keyboard' class='panel'>
<div class='krow'>
<span class='k digit'>7</span>
<span class='k digit'>8</span>
<span class='k digit'>9</span>
<span class='k back'>⭠x</span>
</div>
<div class='krow'>
<span class='k digit'>4</span>
<span class='k digit'>5</span>
<span class='k digit'>6</span>
<span class='k delete'>x⭠</span>
</div>
<div class='krow'>
<span class='k digit'>1</span>
<span class='k digit'>2</span>
<span class='k digit'>3</span>
<span class='k clear'>⇤⋆</span>
</div>
<div class='krow'>
<span class='k empty'></span>
<span class='k digit'>0</span>
<span class='k point'>.</span>
<span class='k plus'><b>+</b></span>
</div>
</div>
</div>
To intercept click
on digit <div>, I have written following Javascript lines
$(document).ready(function ()
{
$('.digit').click(function (ev) { clickDigit(ev); });
...
}
function clickDigit(e)
{
eDigit = e.target;
var sValue = eDigit.innerText;
window.chrome.webview.postMessage("+DIGIT:" + sValue);
}
As you can see, I call postMessage()
function to send a notification to VB.Net code.
To initiaze and display my HTML code, I have written following lines
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeAsync()
End Sub
Async Sub InitializeAsync()
Await wvSelect.EnsureCoreWebView2Async()
wvSelect.NavigateToString(sHtmlText)
End Sub
where WebView2
control is defined in Designer part of my Form
Friend WithEvents wvSelect As Microsoft.Web.WebView2.WinForms.WebView2
Finally, to intercept JavaScript notification, I have written following VB.Net Code
Private Sub wvSelect_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs) _
Handles wvSelect.WebMessageReceived
Dim sValue As String = e.TryGetWebMessageAsString
Dim iPos = sValue.IndexOf(":")
Dim sAction = sValue.Substring(0, iPos)
sValue = sValue.Substring(iPos + 1)
Select Case sAction
Case "+DIGIT"
SendMessage(txtInput.Handle, WM_CHAR, AscW(sValue.Chars(0)), 0)
I hope than what I have reported in this answer can help others users and complete Jimi
answer.
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 | |
Solution 2 | schlebe |