委托和事件在.NET Framework中的應用非常廣泛,然而,較好地理解委托和事件對很多接觸C#時間不長的人來說並不容易。它們就像是一道檻兒,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委托和事件就覺得心里憋得慌,渾身不自在。近日,項目中需要在服務器上搭建一個虛擬儀表界面來實時顯示各外圍設備端連接狀態,使用C#的委托、反射機制解決了問題。由於項目工程代碼比較復雜,現結合一個在工作線程中實時刷新主界面空間內容的Winform小例子,對C#委托方法在桌面應用程序開發中刷新控件功能的方法進行小小的總結。
一、委托的使用方法
簡單說,可以把委托理解為一個通知器,它可以把信息通知給事先綁定好的程序(函數)。我們只需要控制好要兩點:1、委托的綁定;2、處理信息的函數的定義,就可以把委托簡單的使用起來。
public delegate void DelegateTest(可以帶參數); // 定義委托類型
public DelegateTest delegateTest; // 聲明一個委托對象
delegateTest = new DelegateTest(函數名字,比如: FuncTest(...)); // 綁定委托
public void FuncTest(...) // 信息處理函數定義。需要注意的是函數類型,參數類型必須和委托的類型以及參數類型保持一致
{
.... //這樣就可以對委托傳過來的信息進行處理
}
下面看一下具體的小例子,代碼中已經給出詳細的注釋。
一、新建一個C# winform工程,向其中添加一個工作線程類:Work,代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 using System.Threading; 7 8 namespace 更新主界面控件 9 { 10 public class Work 11 { 12 private volatile static Work instanceWork; // 單例 13 14 public delegate void InvokeListBox(int i); 15 public InvokeListBox invokeOthers; 16 17 /// <summary> 18 /// 構造函數 19 /// </summary> 20 public Work() 21 { 22 23 } 24 25 /// <summary> 26 /// 對外接口,獲取單例 27 /// </summary> 28 /// <returns></returns> 29 public static Work GetInstance() 30 { 31 if (null == instanceWork) 32 { 33 instanceWork = new Work(); 34 } 35 36 return instanceWork; 37 } 38 39 /// <summary> 40 /// 業務函數,在工作過程中將狀態傳給主界面 41 /// </summary> 42 public void DoSomething() 43 { 44 for (int i = 0; i < 20; i++) 45 { 46 Thread.Sleep(1000); 47 invokeOthers(i); 48 } 49 } 50 } 51 }
二、主界面布局如下圖所示,
代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 using System.Threading; 11 12 namespace 更新主界面控件 13 { 14 public partial class Form_MainUI : Form 15 { 16 private delegate void InvokeListBox(string strCon); // 刷新ListBox的委托。 17 private InvokeListBox invokeListBox; 18 19 private Work wk; //工作線程對象 20 21 public Form_MainUI() 22 { 23 InitializeComponent(); 24 25 wk = Work.GetInstance(); //單例模式初始化工作線程對象 26 wk.invokeOthers = new Work.InvokeListBox(ReciveData); // 綁定,接收工作線程過來的數據 27 invokeListBox = new InvokeListBox(RefrushListBox); // 綁定,刷新界面ListBox控件 28 } 29 30 /// <summary> 31 /// 啟動工作線程 32 /// </summary> 33 /// <param name="sender"></param> 34 /// <param name="e"></param> 35 private void button_StartWork_Click(object sender, EventArgs e) 36 { 37 Thread th = new Thread(new ThreadStart(wk.DoSomething)); 38 th.Start(); 39 } 40 41 /// <summary> 42 /// 接收工作線程過來的數據,更新界面 43 /// </summary> 44 /// <param name="i"></param> 45 public void ReciveData(int i) 46 { 47 string strConten = i.ToString() + " 更新"; 48 49 if (this.listBox_state.InvokeRequired) 50 { 51 this.listBox_state.Invoke(invokeListBox, new object[] { strConten }); 52 } 53 } 54 55 /// <summary> 56 /// 具體刷新界面函數 57 /// </summary> 58 /// <param name="_str"></param> 59 public void RefrushListBox(string _str) 60 { 61 this.listBox_state.Items.Add(_str); 62 } 63 } 64 }
三、說明:
本例子中有兩個委托:1、Work.cs中的委托變量 ivokeOthers,作用是將信息傳遞給給主界面對應的函數:ReceiveData()。2、Form_MainUI.cs中的委托變量 invokeListBox,作用是刷新界面控件ListBox_state的內容。點擊“開始工作”按鈕后,工作線程啟動,調用Work.cs中DoSomeThing()函數。由於Form_MainUI.cs中的函數ReceiveData()函數綁定了Work.cs中的委托ivokeOthers,所以當Work.cs中DoSomeThing被調用時ivokeOthers會把變量i傳遞給ReceiveData()。ReceiveData()接收到數據后,通過Invoke調用刷函數RefrushListBox()修改主界面ListBox_State的內容。程序運行效果如下:
總結:
1、不要懼怕委托、事件的復雜的概念,動手操作練習一下,就簡單的把它們當做傳遞消息的載體。
2、在工作線程中修改主界面其它控件的內容、狀態、圖片等操作類似,可以自己動手試試。
3、本小結在實現刷新主界面控件的時候使用了單例模式,不使用單例模式也完全可以實現,加上單例是為了讓調用更加方便,在大項目開發中就會體現其優勢。