winform 使用了invoke还是报错 线程间操作无效: 从不是创建控件“Form2”的线程访问它。”

发布时间 2023-11-25 14:31:30作者: lunawzh

winform开发中,遇到“线程间操作无效: 从不是创建控件“Form2”的线程访问它”,明明使用了网上说的this.invoke,怎么还是会报这个错误呢?

代码如下,由于是测试configureAwait功能时发现的,所以带了它的一些使用

 

 private async void button7_Click(object sender, EventArgs e)//点击第一个按钮
        {
            int i = 1;
            if (i == 1)
            {
                await longTask().ConfigureAwait(false);//这里调用长任务处理,使用ConfigureAwait为false,表示不用回到UI线程
            }
            else
            {
                wt("i不等于1");
            }
            wt("UI线程");
        }
        public async Task longTask()
        {
            wt("开始task");
            //一些耗时任务

            await Task.Run(async () =>
             {
                 Form2.Instance.ShowDialog();//弹出 Form2窗体
                 await Task.Delay(5000);
                 wt("窗口关闭");
             }).ConfigureAwait(false);
            await Task.Delay(2000);
            wt("调用窗口任务完成");
        }
        public async Task closeForm2()//点击第二个按钮
        {

            wt("closeForm2");
            await Task.Delay(2000).ConfigureAwait(false);  //等待2s后执行下面语句
            this.Invoke(new Action(() =>//跨线程调用
                {
                    wt("closeForm2_invoke");
                    Form2.Instance.Close();//关闭Form2,但会在这里报错
                }));
            wt("closeForm结束");
        }

      public void wt(string msg)
      {
        Console.WriteLine($"{msg}:{Thread.CurrentThread.ManagedThreadId}");
      }

 

上述代码中,红色表明的地方会报错:线程间操作无效: 从不是创建控件“Form2”的线程访问它。

明明使用了委托了,怎么还会报此错误呢,后研究发现问题出在this.invoke上。

Invoke方法会顺着控件树向上搜索直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。

this指向错了,这里的this指Form1,我们要关闭的是Form2,所以改指就ok了,应改为:

 Form2.Instance.Invoke(new Action(() =>
                {
                    wt("closeForm2_invoke");
                    Form2.Instance.Close();
                }));

 运行的结果