您的位置:首页 > 编程语言 > C#

C#对Windows 窗体控件进行线程安全调用

2013-09-13 16:23 357 查看
  Windows窗体上假设有一个TextBox控件,我们需要在另外的线程中改变它的Text值。

        错误的代码(非安全线程访问)如下:

private Thread demoThread = null;
//在按钮单击事件中新建线程
private void button1_Click(object sender, EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcUnsafe));
this.demoThread.Start();
}
private void ThreadProcUnsafe()
{
//假设存在TextBox控件,名称为textBox1,对其Text属性赋值
this.textBox1.Text = "This text was set unsafely.";
}


        运行,点击“button1”,哦,有异常了:从不是创建控件textBox1(控件名称) 的线程访问它。初看这句话时我的感觉是这些字都认识,就是不明白说得什么(好多异常和说明都有这个特点)。细细琢磨后才反应过来,这句异常的意思是,创建textBox1的线程与访问textBox1的线程不是同一个线程。上例中创建textBox1的线程是在主窗体中,而修改它的值的操作却在另一个线程中,因而无法对textBox1进行访问。由此可得出一个结论:每个线程只能操作自己创建的控件,对于其他线程来说是封闭的,不可访问的。

        当然,这只是一般情况。要想从其他线程访问textBox1,需要使用委托和其他一些属性与方法。请看下面方法。

        正确的做法(线程安全访问):

private Thread demoThread = null;
//委托,实现线程访问控件
delegate void SetTextCallback(string text);
private void button1_Click(object sender, EventArgs e)
{
this.demoThread =new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
//线程调用的方法
private void ThreadProcSafe()
{
this.SetText("This text was set safely.");
}
private void SetText(string text)
{
//使用控件的InvokeRequired属性,该属性比较控件的调用线程与创建线程的ID,若不是同一个线程则执行委托;
//若调用线程与创建线程是同一个线程,则直接访问控件,对其进行操作。
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}


        对于第一种方式,可以在代码中加入这样一句:Control.CheckForIllegalCrossThreadCalls = false;表示不检查控件的非法跨线程调用。程序就可正确运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息