標籤:bsp 線程 ESS mars zh-cn 訊息 close 報錯 對象
WinForm的UI對象只能在UI線程中操作,在非UI線程中操作UI對象,會引發不可預知的錯誤,這時就需要用到Control.Invoke或者Control.BeginInvoke。
使用者線程調用Control.BeginInvoke會向UI訊息佇列發送一個帶委託訊息,Control.BeginInvoke不會阻塞使用者線程,直接返回IAsyncResult對象。
使用者線程調用Control.EndInvoke(IAsyncResult),Control.EndInvoke會阻塞使用者線程,直到委託執行完成,並返回委託的傳回值。沒有傳回值返回null。
Control.Invoke相當於Control.BeginInvoke和Control.EndInvoke的合體,會阻塞使用者線程,直到委託執行完成,並返回委託的傳回值。沒有傳回值返回null。
根據類繼承關係,在視窗中可以直接使用BeginInvoke、EndInvoke、Invoke。
System.Object
??System.MarshalByRefObject
????System.ComponentModel.Component
??????System.Windows.Forms.Control
????????System.Windows.Forms.ScrollableControl
??????????System.Windows.Forms.ContainerControl
????????????System.Windows.Forms.Form
實驗樣本:
表單:
代碼:
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; } }
View Code
System.Windows.Forms.Control.Invoke與BeginInvoke