原文:http://blog.sina.com.cn/s/blog_70bf5798010185i4.html
在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,多个线程对一个变量同时访问是非常危险的
所以在编程中我们可以只用Invoke 和 BeginInvoke 来解决这个问题,使多线程中安全的更新界面显示。
正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。
在编程中,由于界面的更新是很频繁的,所以应尽可能的吧操作对丢给工作线程,尽量让更新界面的UI线程工作量变少
下面说明BeginInvoke的用法
更新窗体中的TextBox..
思路:在主窗口中定义一个委托,其他线程需要进行界面更新的操作时就调用这个委托
如果要在子线程中创建其他窗体,也应该有UI线程来创建,方法类似
namespace test
{
public partial class Form1 : Form
{
//定义一个委托
public delegate void MyInvoke(string str1,string str2);
public Form1()
{
InitializeComponent();
}
public void DoWork()
{
//实例化委托
MyInvoke mi = new MyInvoke(UpdateForm);
//启动委托,让主线程执行操作
this.BeginInvoke(mi, new Object[] {"我是文本框","haha"});
}
public void UpdateForm(string param1,string parm2)
{
this.textBox1.Text = param1+parm2;
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
}
}
}
下面做法是不可取的,不能再多个线程访问同一个变量
//启动一个线程
Thread thread=new Thread(new ThreadStart(DoWork));
thread.Start();
//线程方法
private void DoWork()
{
this.TextBox1.Text="我是一个文本框";
}
===================================================================
经常还会看见另外一种写法,如:
protected void setMsg(string pStr)
{
if (textBox1.InvokeRequired)
{
getTextBack st = new getTextBack(setMsg);
this.Invoke(st, new object[] { pStr });
}
else
{
textBox1.Text += "\n" + pStr + "\n";
}
}
经过debug,可以看出,第一次程序会跑if下面的语句,然后跳出,此时已经启动了委托,接下来,程序会第二次跑进setMsg,但这此textBox1.InvokeRequired为false,说明此次是主线程开始操作了,于是程序会跳过if语句,执行else