I really want to understand and solve this problem I've been struggling with for a few days. I read hundreds of threads and I can't get it to work.
I have a primary form, and on a secondary form a WebView2 control. The purpose is to control the WebView2 from the primary form. They are configured as follows:

My goal is to use the primary form to load some HTML code into the WebView2 from the secondary form, and then take a screenshot of that page. The HTML loading part is working so I will focus next on the screenshot problem. I use this method for taking the screenshot. Which in itself it's working fine when called directly, but it fails when I call it from a thread or a background worker. And yes, this behavior is expected due to the cross-thread calls, I know. Please bear with me!
Ideally, I thought that it should work something like this (oversimplified code):
private void PrimaryForm_Load(...)
{
_secondaryForm = new SecondaryForm();
_secondaryForm.Show();
}
private void Button_Click(...)
{
Thread thread = new Thread(HeavyWork);
thread.Start();
}
private void HeavyWork()
{
// this method will run a few hundred times
Task<string> task = CaptureScreenshotAsync();
string str = task.Result;
// further process the str...
}
private async Task<string> CaptureScreenshotAsync()
{
// it will throw a cross-thread exception
return await _secondaryForm.webView.CoreWebView2.CallDevToolsProtocolMethodAsync("Page.captureScreenshot", "{}");
}
As you can see here I've tried invoking it in a few ways with no luck. Also, making it synchronous. Tried this, this and that - among others. I can't get it to work as it should.
I've also tried to call the HeavyWork method directly like this:
private void Button_Click(...)
{
HeavyWork();
}
But no luck, I either get a cross-thread exception, or a freeze. Like this or this.
The only "hack" I accidentally found on my own is to "sleep" a little bit before getting the task result like this:
private void HeavyWork()
{
Task<string> task = CaptureScreenshotAsync();
Sleep(250);
string str = task.Result;
}
And this is the Sleep method:
private void Sleep(int interval)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < interval)
{
Application.DoEvents();
}
stopwatch.Stop();
}
But this is just a wonky "solution" - sometimes it doesn't work (I assume that because it takes longer to take the screenshot than that wait time). I'm sure that there must be a proper way of handling it. I would greatly appreciate any help. Thanks!



Try it like this: