C# 使用委托實現多線程調用窗體


C#多線程函數如何傳參數和返回值 

提起多線程,不得不提起 委托(delegates)這個概念.

我理解的委托就是 具有 同樣參數和返回值 的函數的集合.
比如

public delegate void MyDelegate(int arg);
就是這種形式的函數 void Myfuntion(int i); 的集合.
如何將一個函數加入 委托 的集合?
MyDelegate dele = new MyDelegate(Myfuntion1);
再增加一個
dele += new MyDelegate(Myfuntion2);

  


...
委托函數 dele 就是 具有整數參數和空返回值的函數 Myfuntion1,2的集合.
調用這個委托函數
dele(1);
就是逐個調用 Myfuntion1,2,...

一般線程函數的聲明和啟動

Thread t = new Thread(new ThreadStart(MyFunction));
t.Start();

  


正是調用了沒有參數和返回值的 委托函數 ThreadStart
其中的參數MyFunction 是 這個委托函數中的一員.

很明顯 這樣無法傳參數和返回值,那我們該怎么辦?

答案就在委托 的BeginInvoke() 方法上, BeginInvoke() 也是(異步)啟動一個新線程.
例如

MyDelegate dele = new MyDelegate (MyFunction);
dele.BeginInvoke(10,"abcd");
void MyFunction(int count, string str);

  


可以實現參數的傳遞.

如何收集線程函數 的 返回值?

與 BeginInvoke 對應 有個 EndInvoke 方法,而且運行完畢返回 IAsyncResult 類型的返回值.
這樣我們可以這樣收集 線程函數的 返回值

MyDelegate dele = new MyDelegate (MyFunction);
IAsyncResult ref = dele.BeginInvoke(10,"abcd");
...
int result = dele.EndInvoke(ref); <----收集 返回值
int MyFunction(int count, string str); <----帶參數和返回值的 線程函數

  

 

提示:"線程間操作無效:從不是創建控件“XX”的線程訪問它"

一般來說,直接在子線程中對窗體上的控件操作是會出現異常,這是由於子線程和運行窗體的線程是不同的空間,因此想要在子線程來操作窗體上的控件,是不可能簡單的通過控件對象名來操作,但不是說不能進行操作,微軟提供了Invoke的方法,其作用就是讓子線程告訴窗體線程來完成相應的控件操作。 現在用一個用線程控制的進程條來說明,大致的步驟如下:

1. 創建Invoke函數,大致如下:

 /// /// Delegate function to be invoked by main thread ///

private void InvokeFun()

{ if( prgBar.Value < 100 )

prgBar.Value = prgBar.Value + 1; }

2. 子線程入口函數: /// /// Thread function interface ///

private void ThreadFun()

{ //Create invoke method by specific function

MethodInvoker mi = new MethodInvoker( this.InvokeFun );

for( int i = 0; i < 100; i++ ) { this.BeginInvoke( mi ); Thread.Sleep( 100 ); } }

3. 創建子線程:

Thread thdProcess = new Thread( new ThreadStart( ThreadFun ) );

thdProcess.Start();

 

出現這個問題主要是因為在線程方法中操作了界面上的控件..lstPrime.Items.Add() 

可以這樣改下.. 

//定義一個委托 
public delegate void MyInvoke(string str); 

//定義一個操作界面的方法 
private void UpdateUI(string str) 
{ 
   //增加項 
   this.lstPrime.Items.Add(str); 
} 


//在線程的方法中,即你的Generate方法.. 
//里面只要是涉及到Items.Add操作的都改成如下形式即可.. 
//比如lstPrime.Items.Add(2);改成: 
MyInvoke mi=new MyInvoke(UpdateUI); 
this.BeginInvoke(mi,new object[]{ "2 "}); 

  




============================================================================



BeginInvokeInvoke的含義[轉載]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(); 

}

為了您的安全,請只打開來源可靠的網址 

打開網站    取消

來自http


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM