在WinFrom应用中,如果需要执行一个较长的时间的调用,或要使用Web Serives从服务器取一些数据,我们通常都会使用多线程来实现这个操作,等操作完成后,再来修改一下一些控件的状态.例如下面的代码,当点击按钮,按钮和文本框都将灰化,操作完成后,再在回调函数中将按钮和文本框设为可用.
上面的代码通常是可以正常运行的,但是存在一个潜在的问题,回调方法并不与调用代码在相同的线程上运行,这意味着它可能会在执行应用程序另一部分的同时执行.为了避免这个问题,就需要在访问可能被程序部分使用的对象时使用同步(如lock),但这种锁定控制而进行独占访问并不是合适,反而会导致系统产生更多的问题,这时我们需要使用Control.Invoke()方法.
Invoke()方法定义在System.Windows.Forms.Control,所有从Ssytem.Windows.Forms.Control继承的类包括From都有这个方法.众所周知,WinFrom的类库是在Win32 API的基础上实现的,而Invoke()方法在底层是用PostMessage函数来实现的,就是说调用Invoke()方法相当于向目标对象只是发送一个消息,对Control的操作还是由用户界面线程来完成,所以这个方法是线程安全的.对以上的代码,只要进行一些修改
//声明一个委托
delegate BooleanCallBack(bool enable);
void BooleanCallBack enableControls;
//在构造函数中初始化
enableControls = new BooleanCallBack(EnableControls);
// 在CallBack中将EnableControls(true)改为
Invoke(enableControls,new object[]{true});
或
建一个帮助类
然后在CallBack函数中将EnableContrls(true)改为
//创建一个Updater对象
Updater updater = new Updater(this.text, this.button, true);
//调用Invoke()方法
Invoke(new MethodINvoker(updater.Update));
进行了这样的处理,多线程对用户界面的操作应该是线程安全的了.
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
class App
{
public static void Main()
{
Application.Run(new MultiThreadedForm());
}
}
class MultiThreadedForm : Form
{
public MultiThreadedForm()
{
// Create a textbox
text.Location = new Point(10, 10);
text.Size = new Size(50, 20);
Controls.Add(text);
// Create a button
button.Text = "Beep";
button.Size = new Size(50, 20);
button.Location = new Point(80, 10);
// Register Click event handler
button.Click += new EventHandler(OnClick);
Controls.Add(button);
}
void OnClick(Object sender, EventArgs args)
{
EnableControls(false);
Thread myThreading = new Thread(new System.Threading.ThreadStart(CallBack));
myThreading.Start();
}
void CallBack()
{
// DoSomething();
//System.Threading.Thread.Sleep(5000);
//MessageBox.Show("OK");
EnableControls(true);
}
void EnableControls(Boolean enable)
{
button.Enabled = enable;
text.Enabled = enable;
}
Button button = new Button();
TextBox text = new TextBox();
}
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
class App
{
public static void Main()
{
Application.Run(new MultiThreadedForm());
}
}
class MultiThreadedForm : Form
{
public MultiThreadedForm()
{
// Create a textbox
text.Location = new Point(10, 10);
text.Size = new Size(50, 20);
Controls.Add(text);
// Create a button
button.Text = "Beep";
button.Size = new Size(50, 20);
button.Location = new Point(80, 10);
// Register Click event handler
button.Click += new EventHandler(OnClick);
Controls.Add(button);
}
void OnClick(Object sender, EventArgs args)
{
EnableControls(false);
Thread myThreading = new Thread(new System.Threading.ThreadStart(CallBack));
myThreading.Start();
}
void CallBack()
{
// DoSomething();
//System.Threading.Thread.Sleep(5000);
//MessageBox.Show("OK");
EnableControls(true);
}
void EnableControls(Boolean enable)
{
button.Enabled = enable;
text.Enabled = enable;
}
Button button = new Button();
TextBox text = new TextBox();
}
上面的代码通常是可以正常运行的,但是存在一个潜在的问题,回调方法并不与调用代码在相同的线程上运行,这意味着它可能会在执行应用程序另一部分的同时执行.为了避免这个问题,就需要在访问可能被程序部分使用的对象时使用同步(如lock),但这种锁定控制而进行独占访问并不是合适,反而会导致系统产生更多的问题,这时我们需要使用Control.Invoke()方法.
Invoke()方法定义在System.Windows.Forms.Control,所有从Ssytem.Windows.Forms.Control继承的类包括From都有这个方法.众所周知,WinFrom的类库是在Win32 API的基础上实现的,而Invoke()方法在底层是用PostMessage函数来实现的,就是说调用Invoke()方法相当于向目标对象只是发送一个消息,对Control的操作还是由用户界面线程来完成,所以这个方法是线程安全的.对以上的代码,只要进行一些修改
//声明一个委托
delegate BooleanCallBack(bool enable);
void BooleanCallBack enableControls;
//在构造函数中初始化
enableControls = new BooleanCallBack(EnableControls);
// 在CallBack中将EnableControls(true)改为
Invoke(enableControls,new object[]{true});
或
建一个帮助类
public class Updater
{
private TextBox textBox;
private Button button;
private bool enabled;
public Updater(TextBox textbox, Button button, bool enabled)
{
this.textBox = textbox;
this.button = button;
this.enabled = enabled;
}
public void Update()
{
this.textBox.Enabled = enabled;
this.button.Enabled = enabled;
}
}
{
private TextBox textBox;
private Button button;
private bool enabled;
public Updater(TextBox textbox, Button button, bool enabled)
{
this.textBox = textbox;
this.button = button;
this.enabled = enabled;
}
public void Update()
{
this.textBox.Enabled = enabled;
this.button.Enabled = enabled;
}
}
然后在CallBack函数中将EnableContrls(true)改为
//创建一个Updater对象
Updater updater = new Updater(this.text, this.button, true);
//调用Invoke()方法
Invoke(new MethodINvoker(updater.Update));
进行了这样的处理,多线程对用户界面的操作应该是线程安全的了.