在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误 的做法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。我们将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用。如果从线程外操作windows窗体控件,那么就需要使用Invoke或者BeginInvoke方法,通过一个委托把调用封送到控件所属的线程上执行。
实例:使用While读取PLC的值显示到面板中
1、第一种实时读取PLC的方法:
private void button1_Click(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(ShowData));
thread.Start(); //使用线程调用
}
//显示实时数据
public void ShowData()
{
while (true)
{
this.Invoke((EventHandler)delegate
{
label1.Text = siemensS7Net.ReadInt16(tb_ad_1).Content.ToString();
label2.Text = siemensS7Net.ReadInt16(tb_ad_2).Content.ToString();
label3.Text = siemensS7Net.ReadInt16(tb_ad_3).Content.ToString();
});
Thread.Sleep(1000);
}
}
2、第二种实时读取PLC的方法:
//声明委托对应的方法
public void ShowData(string param1, string parm2)
{
this.label1.Text = param1;
this.label2.Text = parm2;
}
//声明委托
public delegate void UpdateForm_dl(string str1, string str2);
//调用委托
private void Calldelegate()
{
while (true)
{
Thread.Sleep(1000);
string a = siemensS7Net.ReadInt16(tb_ad_1).Content.ToString();
string b = siemensS7Net.ReadInt16(tb_ad_2).Content.ToString();
this.BeginInvoke(new UpdateForm_dl(ShowData), new object[] { a, b });
}
}
//新线程入口
public void DoWork()
{
Calldelegate();
}
调用
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start(); //使用线程调用
3、第三种实时读取PLC的方法:
两者的区别就是一个导致工作线程等待,而另外一个则不会。BeginInvoke立即插入主线程中执行,而Invoke 要等主线程结束才执行。即:
Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托。
Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。
(一)、Control的Invoke和BeginInvoke
我们要基于以下认识:
(1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的。
(2)Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。
而所谓的“一面响应操作,一面添加节点”永远只能 是相对的,使 UI 线程的负担不至于太大而已,因为界面的 正确更新始终要通过 UI 线程去做,我们要做的事情是在工作线程中包揽大部分的运算, 而 将对纯粹的界 面更 新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的了。
1、Invoke的作用与用法
Invoke()的作用是:在应用程序的主线程上执行指定的委托。
一般应用:在辅助线程中修改UI线程( 主线程 )中对象的属性时,调用this.Invoke();》》线程会在UI线程和辅助线程之间相互转换
4、第四种实时读取PLC的方法: