2009年9月30日星期三

在线程中访问窗体元素

两个Button ,都调用setText函数实现对TextBox1赋值,显示一个字符串Hello。

如果不用子线程,下面的代码可以完全正常的工作。不管点击button1,或者Button2都能正常在文本框中显示Hello.

private void button1_Click(object sender, EventArgs e)
{
setText();
}
private void button2_Click(object sender, EventArgs e)
{
setText();
}
private void setText()
{
textBox1.Text = "Hello";
}

但是,如果在Button2中另起一个子线程,访问textBox1,就会出现异常。

private void button1_Click(object sender, EventArgs e)
{
setText();
}
private void button2_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(setText));
t.Start();
}

private void setText()
{
textBox1.Text = "Hello";
}

为了实现在子线程中对窗体控件的访问,需要使用系统提供的Invoke方法,代码如下。

delegate void SetTextDelegate();

private void button1_Click(object sender, EventArgs e)
{
setText();
}
private void button2_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(setText2));
t.Start();
}

private void setText()
{
textBox1.Text = "Hello";
}

private void setText2()
{
Invoke(new SetTextDelegate(setText));
}

C#中还提供了this.InvokeRequired这个属性,来判断对控件的访问是主线程,还是子线程。应用这个属性,可以在button1_Click 和button2_Click中都统一用setText2,但是需要在setText2中增加一个判断,判断是主线程还是子线程的访问,代码如下。

private void button1_Click(object sender, EventArgs e)
{
setText2();
}
private void button2_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(setText2));
t.Start();
}

private void setText()
{
textBox1.Text = "Hello";
}

private void setText2()
{
if (this.InvokeRequired) //如果是子线程,需要用代理访问。
{
Invoke(new SetTextDelegate(setText));
}
Else //否则直接访问。
{
setText();
}
}

没有评论:

发表评论