如何跨越线程调用窗体控件?(2)
一、前言
VS中,如果UI背后的处理工作复杂,可以启用多线程进行处理,用户不喜欢反应慢的程序。在执行耗时较长的操作时,使用多线程是明智之举,它可以提高程序 UI 的响应速度,使得一切运行显得更为快速。那么如果在UI上反应最新的处理状态呢?这就是如果在子线程(即新开启的处理复杂任务的线程)中更新UI处理状态信息。
二、使用Invoke
引用:http://dev.tot.name/csharp/html/20090314/20090314234018.htm
在Visual Studio 2005/Visual Studio 2008中创建一个C#的Windows窗体应用程序项目,并将其项目命名为UIThreading。程序的功能是为用户输入文字到第1个"TextBox"控件中,并单击"次线程显示"按钮,创建一个次线程,将第1个"TextBox"控件"Text"属性值复制到第2个"TextBox"控件的"Text"属性值中。相应地,如果用户单击"主线程显示"按钮,程序将不会创建新的线程,而是在UI线程中完成属性值的赋值操作。在Visual Studio 2005/Visual Studio 2008的"Form1.cs[设计]"视图中创建基本的窗体布局和控件,控件的命名如图7.36所示。
|
| 图7.36 "跨线程调用窗体控件"布局及命名示意图 |
本例的窗体中,双击"Display"控件和"MainTd"控件可编写其"Click"事件的处理方法,编写Form1.cs如代码7.23所示。
代码7.23 跨越线程调用窗体控件:Form1 .cs
using System; namespace UIThreading void GetTxt(string t) void Method() private void MainTd_Click(object sender, EventArgs e) |
示例程序窗体初始化时,通过信息对话框输出UI线程的ID以作参考。当用户输入文本到"input"控件中,单击"次线程显示"按钮时,程序将跳出信息对话框,输出Method()方法所属线程ID(即新创建的次线程ID),运行结果如图7.37所示。
注意该ID有别于UI的线程ID,说明Method()方法工作于新线程上。在Method()方法中将当前线程阻塞4秒,然后调用GetTxt()方法,并传递t参数(即用户输入值)。GetTxt()方法被调用2次,第1次调用时,GetTxt()方法体首先判断"output"控件的InvokeRequired属性的返回值。如果InvokeRequired属性返回true,则代表当前线程不是UI线程,立即调用"output"控件的Invoke()方法,并传递一个委托对象(指向所属方法)和所接收参数。通过委托在UI线程上第2次调用GetTxt()方法,"output"控件的InvokeRequired属性将返回false,即可直接在主线程上操作该控件,将t参数赋值给"output"控件的Text属性。在第2次调用GetTxt()方法时,将通过信息对话框输出当前所属线程的ID,结果如图7.38所示。
示。
|
| 图7.37 Method方法的所属线程 |
|
| 图7.38 GetTxt方法所属线程 |
由上可知,第2次调用GetTxt()方法时,其所属线程为UI线程,ID和程序窗体创建时所输出的UI线程一致。当用户在信息对话框上单击"确定"按钮后,"output"控件的赋值操作才最终完成,结果如图7.39所示。
|
| 图7.39 窗体控件已被成功调用 |
说明:可以单击"主线程显示"按钮,其操作仅调用了一次GetTxt()方法,而且线程阻塞4秒时,窗体处于无法响应的状态。
解析
在示例程序中,初始化窗体时调用了如以下代码来越过跨线程调用控件的检查
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; |
//方法定义部分 |
以上代码定义了一个方法,在次线程的代码中调用这个方法即可间接调用UI线程中的窗体控件。不过需要注意的是,在程序中首先需要定义了一个委托类型,确保该方法和委托类型的签名一致。





浙公网安备 33010602011771号