BeginInvoke
方法真的是新開一個線程進行異步調用嗎?
參考以下代碼:
public delegate void treeinvoke();
private void UpdateTreeView()
{
??? MessageBox.Show(System.Threading.Thread.CurrentThread.Name);
}
private void button1_Click(object sender, System.EventArgs e)
{
??? System.Threading.Thread.CurrentThread.Name = "UIThread";
??? treeView1.BeginInvoke(new treeinvoke(UpdateTreeView));
}
看看運行結果,彈出的對話框中顯示的是
UIThread
,這說明
BeginInvoke
所調用的委托根本就是在
UI
線程中執行的。
既然是在
UI
線程中執行,又何來
“
異步執行
”
一說呢?
我們再看看下面的代碼:
public delegate void treeinvoke();
private void UpdateTreeView()
{
??? MessageBox.Show(Thread.CurrentThread.Name);
}
private void button1_Click(object sender, System.EventArgs e)
{
??? Thread.CurrentThread.Name = "UIThread";
??? Thread th = new Thread(new ThreadStart(StartThread));
??? th.Start();
}
private void StartThread()
{
??? Thread.CurrentThread.Name = "Work Thread";
??? treeView1.BeginInvoke(new treeinvoke(UpdateTreeView));
}
再看看運行結果,彈出的對話框中顯示的還是
UIThread
,這說明什么?這說明
BeginInvoke
方法所調用的委托無論如何都是在
UI
線程中執行的。
那
BeginInvoke
究竟有什么用呢?
在多線程編程中,我們經常要在工作線程中去更新界面顯示,而在多線程中直接調用界面控件的方法是錯誤的做法,具體的原因可以在看完我的這篇之后看看這篇:
在多線程中如何調用
Winform
,如果你是大牛的話就不要看我這篇了,直接看那篇吧,反正那篇文章我沒怎么看懂。
Invoke
和
BeginInvoke
就是為了解決這個問題而出現的,使你在多線程中安全的更新界面顯示。
正確的做法是將工作線程中涉及更新界面的代碼封裝為一個方法,通過
Invoke
或者
BeginInvoke
去調用,兩者的區別就是一個導致工作線程等待,而另外一個則不會。
而所謂的
“
一面響應操作,一面添加節點
”
永遠只能是相對的,使
UI
線程的負擔不至于太大而以,因為界面的正確更新始終要通過
UI
線程去做,我們要做的事情是在工作線程中包攬大部分的運算,而將對純粹的界面更新放到
UI
線程中去做,這樣也就達到了減輕
UI
線程負擔的目的了。
而在那段更新樹節點的代碼中,其實唯一起作用的代碼是:
System.Threading.Thread.Sleep(100);
,它使
UI
線程有了處理界面消息的機會,其實
數碼幽靈
將問題復雜化了,只要以下的代碼就可以很好的工作了。
private void button1_Click_(object sender, System.EventArgs e)
{
??? TreeNode tn;
??? for(int i=0;i<100000;i++)
??? {
??????? tn=new TreeNode (i.ToString());
??????? this.treeView1.Nodes[0].Nodes.Add(tn);
??????? if (i%100 == 0) Application.DoEvents();
??? }
}