winforms COM例外:在EnsureCoreWebView2Async(null)C#上设置线程模式后,无法更改线程模式

e37o9pze  于 2023-01-05  发布在  C#
关注(0)|答案(2)|浏览(392)

我正在编写一个C#应用程序,该应用程序将加载由外部服务器API生成的技术图表网页。我只是尝试使用WebView2在自定义面板中显示我希望加载的网页(因为原始WebBrowser已弃用,并且Cef存在x64问题)。
但是,以下代码在尝试初始化自定义视图时无法正确执行,并引发com异常:

class ChartView : Panel
    {
#nullable enable
        private string? chartViewFileAddr { get; set; }
#nullable disable

        private WebView2 chartWebView { get; set; }

        private async void ensureWeb2Init() => await chartWebView.EnsureCoreWebView2Async(null);
        private bool isInit = false;

        public ChartView(string? chartViewFileAddr) : base()
        {
            this.chartViewFileAddr= chartViewFileAddr ?? "";
            this.BorderStyle =  BorderStyle.Fixed3D;
            this.Size = new System.Drawing.Size(300, 500);
            this.Location = new Point(0, 320);
            this.Name = "ChartWebView";
            chartWebView= new WebView2();
            chartWebView.Size = this.Size;
            chartWebView.Location = new System.Drawing.Point(0, 0);
            if (isInit == false)
            {
                Task.Run(() => this.ensureWeb2Init()).Wait();
                isInit = true;
            }
            chartWebView.CoreWebView2.Navigate("google.com"); //base address for testing
            this.Controls.Add(chartWebView);
        }

    }

当它运行时,调用ensureWeb2Init失败。如果我尝试在没有等待函数的情况下运行任务,它将无法异步运行,如果我添加等待函数,异步任务将抛出以下内容:

系统.运行时.互操作服务.COMException:'线程模式设置后无法更改。(0x80010106(RPC_E_CHANGED_MODE))'

不管什么原因,我不能让WebView2正确初始化。我在这里做错了什么吗?谢谢你的帮助。

bxgwgixi

bxgwgixi1#

**问题:**正如注解和其他答案中提到的,问题是在UI线程之外的线程中调用方法。

请注意,尽管此方法是异步的并返回Task,但仍必须像大多数UI控件的大多数公共功能一样在UI线程上调用它。
如果此CoreWebView2示例已被释放,或者调用线程不是创建此对象的线程(通常是UI线程),则抛出InvalidOperationException。

**解决方案:**您可能需要根据自己的要求考虑以下解决方案之一:
*设置“源”属性,而不是调用EnsureCoreWebView2Async

您可以设置WebView2.Source属性,如果CoreWebView2尚未初始化,该属性将隐式初始化CoreWebView2。这样您就不需要调用EnsureCoreWebView2Async。例如:

webView21.Source = new Uri("https://google.com");

*公开异步Initialize方法,并等待在需要时调用该方法

如果你需要调用EnsureCoreWebView2Async,你可以公开一个async方法来初始化并等待你需要的时候调用它。
为控件定义以下方法:

public async Task InitializeControl(string url)
 {
     await webView21.EnsureCoreWebView2Async();
     webView21.CoreWebView2.Navigate("https://google.com");
 }

当你想初始化它的时候,可以这样使用它:

private async void Form1_Load(object sender, EventArgs e)
 {
     await myControl.InitializeControl("https://www.google.com");
 }

*调用EnsureCoreWebView2Async而不等待,然后在CoreWebView2InitializationCompleted事件的事件处理程序中执行其余初始化

您可以调用EnsureCoreWebView2Async而无需等待,然后只需在CoreWebView2InitializationCompleted事件处理程序中执行初始化即可。

webView21.CoreWebView2InitializationCompleted += (obj, args) =>
 {
     webView21.CoreWebView2.Navigate("https://google.com");
 };
 webView21.EnsureCoreWebView2Async();

更多信息和参考:

zengzsys

zengzsys2#

此异常意味着代码必须在UI线程(特别是创建控件的UI线程)上运行。这对于UI COM组件很常见。
您发布的代码使用Task.Run在线程池线程上执行代码。若要在UI线程上运行它,请删除Task.Run

相关问题