线程的一些疑问
我们知道自己定义的一个线程是无法操作控件的,这是因为控件在创建的时候本身是有一个线程程的,那么这个线程到底是什么样子呢,能不能显示用代码的描述一下,多谢了
你从Main函数开始执行启动一个窗体,实际上就是在一个线程上运行的。这个线程我们取个名字叫UI线程。它是随你应用程序启动就开始存在的。和用户交互的窗体等界面元素的显示、行为都在这个线程上。如果你自己创建了线程,在这个线程上访问UI线程上的控件不是那么容易,因为两个线程对一个资源的访问涉及到资源状态是否一致的问题。但是要在另一个线程上操纵UI上控件并不是没有可能,这时要采用Invoke封送跨线程调用。
假设在窗体内含一个Label控件Label1,我们要设置其Text属性的值,可如下:
声明一个委托:
delegate void SetTextHandler(string Text);
构造一个方法:
void SetLabel1Text(string Text)
{
if (Label1.InvokeRequired)
{
this.Invoke(SetTextHandler(SetLabel1Text), Text);
}
else
{
Label.Text = Text;
}
}
解释:
实际上这是构造一个在两个线程都可以使用的方法。
当你在自己的线程上调用该方法时,Label1.InvokeRequired = true,从而将SetLabel1Text方法本身封装到委托中进行封送,Invoke将方法封送到UI线程,其中Invoke的第二个参数(object类型)用来传递调用SetLabel1Text所需的参数,也就是Text形参。
封送以后,在UI线程上,将使用封送的Text参数值重新调用SetLabel1Text方法,这时Label1.InvokeRequired = false,因为在UI线程,因此直接用Text参数赋予Label1.Text属性,从而改变其值。
另外,如果你想让多个线程运行的模式更像.net1.1风格,可以在应用程序入口Main的Application.Run()方法前,设置System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls静态属性设置为false,禁止运行时跨线程调用合法性检查。
这样,你就可以轻松在另外的线程上直接使用Label1.Text = "SomeThing";这样的普通方式对Label1控件赋值。但是你需要承担资源访问状态不一致的风险,而且很有可能造成死锁而使应用程序崩溃,所以不建议这样做。