winforms 如何在WebView2中从ExecuteScriptAsync获取同步返回

yrefmtwq  于 2023-10-23  发布在  其他
关注(0)|答案(5)|浏览(444)

.NET、WinForms。
调用是从UI线程触发的(按钮-点击)。ExecuteScriptAsync的返回应该继续同步处理,即它们应该再次与呼叫上下文同步。我失败了。
我试着举个例子:

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

这也不起作用(参见错误):

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

我为一个代码样本投标。

ohfgkhjo

ohfgkhjo1#

要从ExecuteScriptAsync中获取结果,请使用await运算符,如下所示:

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

**注意:**对于那些想要使用WebView2的人,您需要在您的机器上安装WebView2 RuntimeMicrosoft Edge Chromium。您还需要在项目中安装WebView2 NuGet package

ymdaylpp

ymdaylpp2#

我可能不得不这样使用它。这是我能找到的最好的解决方案:

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

    }
suzh9iv8

suzh9iv83#

我使用了我自己的解决方案,这对我来说是有效的,但我不知道它是否会在未来引起任何问题(如果有人知道,请添加评论)。它会等待2秒让脚本执行,然后跳出:

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

js81xvg64#

对于任何在WinForms下使用WebView2并寻找安全,简单和防阻塞解决方案的人来说,这些代码行似乎是合乎逻辑的:

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* 是用户定义的,并在 Async 进程开始之前分配。

从main方法调用此方法:

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

现在从这个方法调用这些helper方法:

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

g52tjvyc5#

webView.ExecuteScriptAsync("Math.sin(Math.PI/2)").Result;

相关问题