使用Invoke解决多线程间的控件访问出错
转自
在一个WinForm界面上有一个按钮(button1)和一个文本框(textBox1),在button1的点击事件处理程序中创建一个新的线程,并期望在新线程中更改textBox1的值,容易出错的代码如下:
// 按钮点击事件处理程序 private void button1_Click( object sender, EventArgs e){ // 创建新线程 Thread processorThread = null ; processorThread = new Thread( new ThreadStart(Done)); processorThread.IsBackground = true ; processorThread.SetApartmentState(ApartmentState.STA); processorThread.Start();} // 更新textBox1值 private void Done(){ textBox1.Text = " www.mzwu.com " ;}
运行程序点击按钮后出错,提示:线程间操作无效: 从不是创建控件“textBox1”的线程访问它。下边我们用Invoke解决这一问题:
// 按钮点击事件处理程序 private void button1_Click( object sender, EventArgs e){ // 创建新线程 Thread processorThread = null ; processorThread = new Thread( new ThreadStart(Done)); processorThread.IsBackground = true ; processorThread.SetApartmentState(ApartmentState.STA); processorThread.Start();} // 定义委托 delegate void WriteInvoke( string msg); private void Write( string msg){ textBox1.Text = msg;} // 更新textBox1值 private void Done(){ this .Invoke( new WriteInvoke(Write), new object [] { " www.mzwu.com " });}
更新成功!
总结一下:在当前线程中不允许直接调用在其他线程实例化的对象,因为这种操作是线程不安全的,编译器是禁止的。但我们常常希望达到这样的目的,比如创建一个辅助线程,在辅助线程中创建WebClient对象,用来发送信息,然后把接收到的信息反馈到主线程的某个对象。这时我们就可以使用委托的方法来达到,主要步骤是把原先非法调用对象的语句单独写成更新函数,定义一个函数委托类并串接更新函数进行实例化,最后在需要更新的地方调用Invoke方法即可达到目的。