最近在一個demo中了解到可以用BeginInvoke來處理異步,於是我也自己做了一個winform來學習BeginInvoke。
在窗體上放置了一個按鈕和一個label,點擊按鈕3秒后再label上顯示“Hello World”。先是有了如下代碼:
1 private void btnStart_Click(object sender, EventArgs e) 2 { 3 BeginInvoke(new xDel(k => 4 { 5 Thread.Sleep(k); 6 txtMain.Text = "Hello World"; 7 }), 3000); 8 } 9 10 delegate void xDel(int i);
點擊按鈕后調用BeginInvoke執行異步,傳遞一個委托。按照我的設想,應該BeginInvoke應該是創建一個新線程執行委托,所以不會造成UI假死。
但是結果是運行后UI還是假死了。
后來上網查找了一些資料才發現,原先看的demo里使用的委托的BeginInvoke方法,而我寫的BeginInvoke是屬於Control類的。正確的寫法應該是:
1 private void btnStart_Click(object sender, EventArgs e) 2 { 3 xDel xd = new xDel(t => 4 { 5 Thread.Sleep(t); 6 BeginInvoke(new Action(() => 7 { 8 txtMain.Text = "Hello World"; 9 })); 10 }); 11 xd.BeginInvoke(3000, null, null); 12 } 13 14 delegate void xDel(int i);
這兩者的區別在於委托的BeginInvoke方法是新起一個線程來執行委托,而原線程繼續往下執行;Control.BeginInvoke則是將委托強制傳遞至UI線程執行,所以可能會造成UI線程假死。
所以想要執行異步,應該用delegate的BeginInvoke方法;而Control.BeginInvoke方法主要用途是讓子線程可以跨線程操作UI線程的控件,正如代碼2的第六行一樣。