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处理。

浙公网安备 33010602011771号