Reputation: 312
.NET, WinForms.
The calls are triggered from the UI thread (buttons - clicks). The returns from ExecuteScriptAsync should continue to be processed synchronously, i.e. they should be synchronized again with the call context. I fail here.
I tried for example:
private void buttonTest1_Click(object sender, EventArgs e) {
MessageBox.Show(GetMathResult());
}
String GetMathResult() {
// a) Application freezes
//var result = webView.ExecuteScriptAsync("Math.sin(Math.PI/2)").GetAwaiter().GetResult();
//return result;
// b) return null
//String result = null;
//Task task = new Task(async () => { result = await webView.ExecuteScriptAsync("Math.sin(Math.PI/2)"); });
//task.RunSynchronously();
//return result;
// c) Excepion: // InvalidCastException: Das COM-Objekt des Typs "System.__ComObject" kann nicht in den Schnittstellentyp "Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Controller" umgewandelt werden. Dieser Vorgang konnte nicht durchgeführt werden, da der QueryInterface-Aufruf an die COM - Komponente für die Schnittstelle mit der IID "{4D00C0D1-9434-4EB6-8078-8697A560334F}" aufgrund des folgenden Fehlers nicht durchgeführt werden konnte: Schnittstelle nicht unterstützt(Ausnahme von HRESULT: 0x80004002(E_NOINTERFACE)).
//String result = Task.Run(() => GetMathResultTask()).Result;
//return result;
}
Task<String> GetMathResultTask() {
return webView.ExecuteScriptAsync("Math.sin(Math.PI/2)");
}
And that doesn't work either (see error):
private void buttonTest3_Click(object sender, EventArgs e) {
MessageBox.Show(Y());
}
String Y() {
String result = null;
var autoResetEvent = new AutoResetEvent(false);
Task.Run(async () =>
{
try {
result = await webView.ExecuteScriptAsync("Math.sin(Math.PI/2)");
}
catch (Exception exc) {
// !!! {"Das COM-Objekt des Typs \"System.__ComObject\" kann nicht in den Schnittstellentyp \"Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Controller\" umgewandelt werden. Dieser Vorgang konnte nicht durchgeführt werden, da der QueryInterface-Aufruf an die COM-Komponente für die Schnittstelle mit der IID \"{4D00C0D1-9434-4EB6-8078-8697A560334F}\" aufgrund des folgenden Fehlers nicht durchgeführt werden konnte: Schnittstelle nicht unterstützt (Ausnahme von HRESULT: 0x80004002 (E_NOINTERFACE))."}
Console.WriteLine(exc.ToString());
}
finally {
autoResetEvent.Set();
}
});
autoResetEvent.WaitOne();
return result;
}
I am bidding for a code sample.
Upvotes: 6
Views: 20738
Reputation:
For Anyone working with WebView2 under WinForms and looking for Safe, Simple and Anti-Blocking Solution these lines of codes may seem logical:
public void WaitAsyncTask(int waitSecond, System.Runtime.CompilerServices.TaskAwaiter activeTask)
{
double secondDiffer = (DateTime.Now - WaitStartTime).TotalSeconds;
while (secondDiffer < waitSecond)
{
secondDiffer = (DateTime.Now - WaitStartTime).TotalSeconds;
Application.DoEvents();
if (activeTask.IsCompleted)
break;
}
}
WaitStartTime is user defined and assigned before Async process start.
To call this method from main method:
public async Task ExecJavaScript(string userScript)
{
MacroJava = "";
var tr = await ((Microsoft.Web.WebView2.WinForms.WebView2)wbSelectedTech).CoreWebView2.ExecuteScriptAsync(userScript);
MacroJava = System.Text.Json.JsonSerializer.Deserialize<dynamic>(tr);
MacroJava = MacroJava is null ? "" : MacroJava.ToString();
}
Now call these helper methods from this method:
public string GetelementValue(string elmId)
{
var aw = ExecJavaScript("document.getElementById('" + elmId + "').innerHTML").GetAwaiter();
TimeWaitStart = DateTime.Now;
WaitAsyncTask(2, aw);//for 2 seconds maximum
return MacroJava.ToString();
}
Upvotes: 2
Reputation: 125
I used my own solution which worked for me, but I don't know if it can cause any problems in the future (if someone knows, please add comment). It waits 2 seconds for script to execute before jumping out:
int max_count = 200;
var task = webView2.ExecuteScriptAsync(script);
while (!task.IsCompleted && --max_count > 0)
{
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
if (max_count > 0)
{
result = JsonConvert.DeserializeObject(task.Result)?.ToString() ?? "";
}
else
{
// Timeout
}
Upvotes: 2
Reputation: 125197
To get the result from ExecuteScriptAsync
use await
operator, like this:
private async void Form1_Load(object sender, EventArgs e)
{
await this.webView21.EnsureCoreWebView2Async();
}
private async void button1_Click(object sender, EventArgs e)
{
var result = await webView21.ExecuteScriptAsync("Math.sin(Math.PI/2)");
MessageBox.Show(result);
}
Note: For those who want to use WebView2
, you need to have WebView2 Runtime and Microsoft Edge Chromium installed on your machine. You also need to install WebView2 NuGet package in your project.
Upvotes: 9
Reputation: 312
I will probably have to use it that way. This is the best solution I could find:
private void buttonTest3_Click(object sender, EventArgs e) {
GetMathResult_v3((x) => {
MessageBox.Show(x);
// ..
});
}
void GetMathResult_v3(Action<String> callbackAction) {
var task = webView.ExecuteScriptAsync("Math.sin(Math.PI/2)");
task.ContinueWith(
(x) => {
String mathResult = x.Result;
callbackAction(mathResult);
}
, TaskScheduler.FromCurrentSynchronizationContext()
);
}
Upvotes: 5