How to wait for an element to be visible with time out in WebView2 in .NET 6.0. Specifically how to access UI thread

126 Views Asked by At

In .NET 6.0 using WebView2, I'm trying to wait for a period of time to see if an element becomes visible in the DOM (essentially what Selenium WebDriverWait does, but in WebView2).

I think this code should do that:

internal async Task<bool> WaitForElementToBeVisible(FormWebView2 formWebView2, string element, int numberOfSecondBeforeTimingOut) 
{
    using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    CancellationToken cancellationToken = cancellationTokenSource.Token;

    try 
    {
        await Task.Run(async () => {
                while (true) {
                    cancellationToken.ThrowIfCancellationRequested(); // Stop the task if cancelled in the outer catch
                    string webPage = await formWebView2.webView2.ExecuteScriptAsync("document.documentElement.innerHTML"); // Get the web page using JavaScript
                    string decodedWebPage = System.Text.RegularExpressions.Regex.Unescape(webPage);

                    if (decodedWebPage.Contains(element))
                        break; // Stop checking

                    await Task.Delay(100); // Wait 1/10th of a second before checking again
                }
            }).WaitAsync(TimeSpan.FromSeconds(numberOfSecondBeforeTimingOut));

        // If the task ran to completion, ie the element exists,
        Debug.WriteLine("Element exists");

        return true;
    }
    catch (TimeoutException) 
    { 
        // If the task created in try timed out,
        Debug.WriteLine("Timed out after " + numberOfSecondBeforeTimingOut + " seconds");
        cancellationTokenSource.Cancel(); // Cancel the task
        return false;
    }
}

When I run it, I get an error:

System.InvalidOperationException: CoreWebView2 can only be accessed from the UI thread.

I'm way over my head trying to figure out how to run this on the UI thread. Creating and starting a task on the UI thread looks helpful, but the answer no longer seems to be available in .NET 6.0.

Suggestions, hopefully with sample code, would be very welcome.

1

There are 1 best solutions below

0
Pan ache On

This works using a Stopwatch to check for a time out:

     internal async Task<bool> WaitForElementToExist(FormWebView2 formWebView2, string element, int secondToWait) {
        string webPage = await formWebView2.webView2.ExecuteScriptAsync("document.documentElement.innerHTML"); // Get the web page using JavaScript
        string decodedWebPage = Regex.Unescape(webPage);
        int numberOfMillisecondsToWait = secondToWait * 1000; // Convert to milliseconds
        bool elementExists = false;
        Stopwatch stopwatch = new Stopwatch();// Create new stopwatch
        stopwatch.Start();// Begin timing
        while (stopwatch.ElapsedMilliseconds < numberOfMillisecondsToWait) { // While it has not timed out,
            if (decodedWebPage.Contains(element)) { // If the element is in the DOM,
                elementExists = true;
                break; // Stop checking
            }
            await Task.Delay(100); // Wait 1/10th of a second before checking again

            // Check the web page that currently exists
            webPage = await formWebView2.webView2.ExecuteScriptAsync("document.documentElement.innerHTML"); // Get the web page using JavaScript
            decodedWebPage = Regex.Unescape(webPage);
        }
        stopwatch.Stop(); // Stop the stopwatch
        return elementExists;
    }