C#使用中的-Invoke

本文介绍了C#中Invoke和BeginInvoke的使用方法,包括如何在支路线程中调用它们以更新主界面。文章详细解释了Invoke和BeginInvoke的调用过程及其区别,并提供了具体的代码示例。

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

C#: Control中的Invoke的使用。Invoke和BeginInvoke一般是在支路线程中调用,用来更新主界面。Invoke在拥有此控件的基础窗口句柄的线程上执行指定的委托;BeginInvoke在创建控件的基础句柄的线程上异步执行指定的委托。

Invoke的调用:

using System;
	using System.Threading;
	using System.Windows.Forms;
	namespace test20180818
	{
	    public partial class Form1 : Form
	    {
	        public Form1()
	        {
	            InitializeComponent();
	        }
	        private Thread invokeThread;
	        private delegate void InvokeDelegate();
	        private void button1_Click(object sender, EventArgs e)
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "1");
	            invokeThread = new Thread(new ThreadStart(StartMethod));
	            invokeThread.Start();
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"2");
	        }
	        private void StartMethod()
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"3");
	            button1.Invoke(new InvokeDelegate(invokeMethod));
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"4");       
	        }
	        private void invokeMethod()
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"5");
	         }
	      }
	    }

执行的结果为:1-》并行的结果2和3-》5-》4
1------>2和StartMethod()中的3同时得到----->3执行完,不管2有没有执行完,InvokeThread把消息封送(Invoke)给UI线程,然后自己等待)---->UI线程处理完button1_Click后,处理InvokeThread封送过来的消息,执行InvokeMethod方法,即5,处理往后UI线程切换到invokeThread线程,最后得到4。

BeginInvoke的写法同上,把Invoke替换成BeginInvoke即可测试结果。

    using System;
	using System.Threading;
	using System.Windows.Forms;
	namespace test20180818
	{
	    public partial class Form1 : Form
	    {
	        public Form1()
	        {
	            InitializeComponent();
	        }
	        private Thread beginInvokeThread;
	        private delegate void beginInvokeDelegate();
	        private void button1_Click(object sender, EventArgs e)
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "1");
	            beginInvokeThread = new Thread(new ThreadStart(StartMethod));
	            beginInvokeThread.Start();
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"2");
	        }
	        private void StartMethod()
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"3");
	            button1.BeginInvoke(new InvokeDelegate(beginInvokeMethod));
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"4");       
	        }
	        private void beginInvokeMethod()
	        {
	            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"5");
	         }
	      }
	    }

1在UI线程上执行----->beginInvokeThread线程开始执行,UI继续执行代码段2,并发地invokeThread执行代码段3-------------->不管UI有没有执行完代码段2,这时beginInvokeThread线程把消息封送给UI,自己并不等待,继续向下执行-------->UI处理完button1_Click消息后,处理beginInvokeThread线程封送过来的消息。
能够区分他们分别是执行在哪个线程上的。有线程UI/线程begininvokeThread/线程invokeThread
注:以上1、2、3、4、5分别是输出打印的字符所在段落的代码

C#为控件单独开辟了一个线程,当另外一个线程的方法需要修改控件或者调用控件的方法时,需要通过控件的InvokeRequired方法来进行。比如,当另一个线程想调用控件的方法时:

  //定义委托
private delegate void SendCallBack(List<byte[]> bufferList,bool  feedback);
//Send方法属于某个窗口
private void Send(List<byte[]> bufferList,bool feedback) {
            if (this.InvokeRequired) {                          //跨线程调用时的执行逻辑
                try {
                    SendCallBack cb = new SendCallBack(Send);
                    this.Invoke(cb,bufferList,feedback);
                } catch(Exception ex) {
                    MessageBox.Show(ex.Message);
                }        
            } 
           else 
           {
           //不是跨线程调用此方法时的执行逻辑
           }      }
           
private void serialPort1_DataReceived(object sender,SerialDataReceivedEventArgs e) {
    Send(bufferlist,true);
}  

控件的InvokeRequired属性:bool值,为true时表示调用Send方法的是另一个线程,此时需要将Send方法传送给一个委托让委托所在的线程来代替执行Send方法;为false时表示Send的调用者没有跨线程调用Send方法,此时直接执行else中的代码即可。
串口的DataReceived事件和Send方法所属的窗口不在同一个线程,因此在serialPort1_DataReceived事件中调用Send方法时就会执行Send方法中if块中的代码。

this.InvokeRequired
说白了,判断当前线程是否是UI线程。
如果this.InvokeRequired = true,你需要通过this.Invoke()传递委托去操作界面。否则直接操作即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值