C# Invoke

本文介绍了如何解决在非主线程中更新TabControl时遇到的竞争条件错误。通过使用Invoke和BeginInvoke方法,可以安全地在主线程中更新界面元素,避免了线程间操作导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要在程序中实现在一个线程中添加tabPage的问题,但是tabControl实在主进程中建立的,所以在运行时报错:线程间操作无效: 从不是创建控件“tabControl1”的线程访问它。

然后在网上查,需要用Invoke,delegate。网上有很多关于这些的资料,有些写的挺好的,看了感觉挺明白。

下面这段是网上的:

Invoke或者BeginInvoke方法都需要一个委托对象作为参数。委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。如果其它线程直接操作界面线程所属的控件,那么将会产生竞争条件,造成不可预料的结果。

使用Invoke完成一个委托方法的封送,就类似于使用SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。

使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。

但是在内部实现上,InvokeBeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。

 

我一开始是直接在线程里添加tabpage,下面这样,然后就报错

		  TabPage tp = new TabPage();
                    tp.Name = str.Substring(2);
                    tp.Text = str_in.Substring(1);
                    ListView lv = new ListView();
                    lv.Dock = System.Windows.Forms.DockStyle.Fill;
                    this.tabControl1.Controls.Add(tp);
                    tp.Controls.Add(lv)

后来用invoke

在线程中就这两句,将上面的操作卸载了addPage函数里,当然在一开始要声明public delegate void MyInvoke();

		  MyInvoke mi = new MyInvoke(addPage);
                    this.BeginInvoke(mi);

 

 private void addPage()
        {
            TabPage tp = new TabPage();
            tp.Name = str.Substring(2);
            tp.Text = str_in.Substring(1);
            //ListView lv = new ListView();
            //lv.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tabControl1.Controls.Add(tp);
            //tp.Controls.Add(lv);
        }


 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值