WinForm的UI對象只能在UI線程中操做,在非UI線程中操做UI對象,會引起不可預知的錯誤,這時就須要用到Control.Invoke或者Control.BeginInvoke。windows
用戶線程調用Control.BeginInvoke會向UI消息隊列發送一個帶委託消息,Control.BeginInvoke不會阻塞用戶線程,直接返回IAsyncResult對象。async
用戶線程調用Control.EndInvoke(IAsyncResult),Control.EndInvoke會阻塞用戶線程,直到委託執行完成,並返回委託的返回值。沒有返回值返回null。ide
Control.Invoke至關於Control.BeginInvoke和Control.EndInvoke的合體,會阻塞用戶線程,直到委託執行完成,並返回委託的返回值。沒有返回值返回null。this
根據類繼承關係,在窗口中能夠直接使用BeginInvoke、EndInvoke、Invoke。spa
System.Object
System.MarshalByRefObject
System.ComponentModel.Component
System.Windows.Forms.Control
System.Windows.Forms.ScrollableControl
System.Windows.Forms.ContainerControl
System.Windows.Forms.Form線程
實驗示例:調試
窗體:code
代碼:component
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // 在非UI線程中操做UI對象,調試運行會報錯。 // 直接運行會使程序置於不可預知風險之中。 new Thread(() => { progressBar1.Value = 100; }).Start(); } private void button2_Click(object sender, EventArgs e) { new Thread(() => { var result = this.Invoke(new Func<int, int, string>((n1, n2) => { for(int i = 0; i <= 100; i += 10) { progressBar1.Value = i; Thread.Sleep(200); } return (n1+n2).ToString(); }), 100, 21); MessageBox.Show(result.GetType().ToString() + ":" + result); }).Start(); } private void button3_Click(object sender, EventArgs e) { new Thread(() => { IAsyncResult asyncResult = this.BeginInvoke(new Func<int, int, string>((n1, n2) => { for (int i = 0; i <= 100; i += 10) { progressBar1.Value = i; Thread.Sleep(200); } return (n1 + n2).ToString(); }), 200, 32); MessageBox.Show("BeginInvoke不會阻塞"); var result = this.EndInvoke(asyncResult); MessageBox.Show("EndInvoke會阻塞," + result.GetType().ToString() + ":" + result); }).Start(); } private void button4_Click(object sender, EventArgs e) { // 連續給兩個委託,因爲UI線程只有一個,兩個委託只能前後執行 new Thread(() => { IAsyncResult asyncResult1 = this.BeginInvoke(new Func<int, int, string>((n1, n2) => { for (int i = 0; i <= 100; i += 10) { progressBar1.Value = i; Thread.Sleep(200); } return (n1 + n2).ToString(); }), 200, 32); IAsyncResult asyncResult2 = this.BeginInvoke(new Func<int, int, string>((n1, n2) => { for (int i = 0; i <= 100; i += 10) { progressBar2.Value = i; Thread.Sleep(200); } return (n1 + n2).ToString(); }), 400, 64); MessageBox.Show("BeginInvoke不會阻塞"); var result1 = this.EndInvoke(asyncResult1); MessageBox.Show("EndInvoke(asyncResult1)返回"); var result2 = this.EndInvoke(asyncResult2); MessageBox.Show("EndInvoke(asyncResult2)返回"); MessageBox.Show( result1.GetType().ToString() + ":" + result1 + "\r\n" + result2.GetType().ToString() + ":" + result2); }).Start(); } private void button5_Click(object sender, EventArgs e) { // 要等精度條更新完成後,點擊才能響應 MessageBox.Show("ha"); } private void button6_Click(object sender, EventArgs e) { progressBar1.Value = 0; progressBar2.Value = 0; } }