InvokeRequired属性与Invoke方法

MSDN中说:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性 。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。

结合在项目中遇到的一个例子:

 1  public partial class ProgressForm : Form {
 2         public ProgressForm() {
 3             InitializeComponent();
 4         }
 5 
 6         public void ShowMessage(string msg,bool canCancel) {
 7             if (InvokeRequired) {
 8                 Invoke(new Action(() => {
 9                                       _lbMessage.Text = msg;
10                                       _btnCancel.Visible = canCancel;
11 
12                                   }));
13             } else {
14                 _lbMessage.Text = msg;
15                 _btnCancel.Visible = canCancel;
16             }
17         }
18 
19         public void CloseForm() {
20             if (InvokeRequired) {
21                 Invoke(new Action(Close));
22             } else {
23                 Close();
24             }
25         }
26 
27         public void ShowError(Exception exception) {
28             if (InvokeRequired) {
29                 Invoke(new Action<Exception>(DisplayError), exception);
30             } else {
31                DisplayError(exception);
32                 
33             }
34         }
35 
36         private void DisplayError(Exception e) {
37             _lbMessage.Text = "Action runs in error! " + e.Message;
38             _lbMessage.ForeColor = Color.Red;
39             _btnOK.Visible = true;
40             _btnCancel.Visible = false;
41         }
42 
43         private void _btnCancel_Click(object sender, EventArgs e) {
44             if (CancelClick != null) {
45                 CancelClick();
46             }
47         }
48 
49         public event Action CancelClick;
50 
51     }

简单的说,如果有两个线程,Thread A和Thread B,并且有一个Control c,是在Thread A里面new的。那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。相反,如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true。是否是UI线程与结果无关。(通常Control所在的线程是UI线程,但是可以有例外)也可以认为,在new Control()的时候,control用一个变量记录下了当前线程,在调用InvokeRequired时,返回当前线程是否不等于new的时候记录下来的那个线程。如果InvokeRequired==true表示其它线程需要访问控件,那么调用invoke来转给控件owner处理。

posted @ 2012-05-31 22:53  桥边红药  Views(618)  Comments(0)    收藏  举报