先看看示例效果
按照國際慣例,得先說說概念。
以上內容來自MSDN。
【委托】
概念和代碼都有了。剩下的就是應用了,要是只知道概念不會用,那還是等於不會。
要用委托首先要明確幾個問題:
1、為什么需要委托?什么場合用?
我也不想使用委托,誰沒事想多些代碼。但是在某一天,我寫代碼的時候,在多線程中訪問了 UI 控件,發現不行。於是乎百度一大堆,結果就是用委托。官方也有這樣的Demo,具體自己百度。於是乎得到一個答案,多線程訪問 UI 控件得借助委托。其他的場景不說了,其實大部分都是多線程和異步的場景需要。到這里我們就明白了,委托這東西,可以在多線程或者異步操作中發揮大作用,可以在窗體間傳參,而且還很安全。
2、怎么使用?
委托的使用也是比較容易的。
1)、定義委托
2)、聲明委托對象
3)、實例化委托
4)、調用委托(執行方法)
來點實際的代碼,多線程中訪問 UI 控件:
public delegate void UpdateTextEventHandler(string strText); // 1、定義委托類型 public UpdateTextEventHandler UpdateText; // 2、聲明委托對象public FrmMain() { InitializeComponent(); UpdateText = OnUpdateText; // 3、實例化委托對象,這里編譯后就不是這樣子了,而是有個 new 操作 } private void OnUpdateText(string strText) { labTest.Text = strText; } private void btnThreadOperateControl_Click(object sender, EventArgs e) { new Task(() => { // 這里就不得不使用委托了,否則會報錯,提示大概意思就是“不能再其他線程訪問控件" for (int i = 0; i < 1000; i++) { // 自定義委托方式 //Invoke(UpdateText, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 采用泛型委托簡化后 Invoke(new Action<string>(strText => labTest.Text = strText), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); System.Threading.Thread.Sleep(10); } }).Start(); }
以上代碼比較簡單,但可以解決一些基本的多線程訪問控件問題。現實場景有:后台多線程操作業務,打印操作日志到主界面Text框。后台采集數據,更新到主界面Chart。
當然,委托作為C#的一個很核心的東西,遠不止這些內容。有多播委托,將委托作為函數參數進行封裝等。
委托類似:c/c++中的函數指針封裝版,MFC/C++Builder中的PostMessage/SendMessage封裝版,Qt中的信號槽。
一道華麗的分割線
【事件】
使用事件也要弄清楚幾個問題
1、為什么使用委托?什么場合用?
事件是對多播委托的一個封裝,主要是限制誰發布事件,誰觸發。比如自己定義一個類,類里面有個事件,那么只能你來觸發,響應在別人那邊。事件多用於UI操作,但不代表非UI不可以使用。窗體程序將這一點體現的淋漓盡致。
2、怎么使用?
事件的使用也是比較容易的。
1、由於事件是基於委托的,那么你得先定義一個委托類型
2、聲明委托對象,並用event關鍵字修飾
3、在聲明事件的類內部使用(誰聲明的,誰觸發)
4、在聲明事件的類的外部綁定(沒有聲明的,那你就來訂閱(綁定 +=)事件)
來點實際代碼:
using System; namespace EventDemo { public delegate void TestEventHandler(); class Program { static void Main(string[] args) { Class1 class1 = new Class1(); class1.Test1 = Test; // 委托調用,這里代表是Program類調用class1.Test1(),可不能理解成class1調用 class1.Test1(); class1.Test += Test; // 事件調用,這里對事件的體現不是很明顯,因為能看到調用了DoSomething。 // 雖然調用了DoSomething,但是事件是在Class1內部調用的 class1.DoSomething(); Console.WriteLine("Press any key to close the application..."); Console.ReadKey(true); } static void Test() { Console.WriteLine("hello world."); } } class Class1 { public TestEventHandler Test1; // 聲明委托對象 public event TestEventHandler Test; // 聲明事件對象 public void DoSomething() { Test?.Invoke(); } } }
個人經驗分享2句話區分委托和事件:
1、委托一般是自己聲明,別人調用。
2、事件是自己聲明,自己調用,但是響應在別人那邊。
看完了這些,不要以為你就會使用委托和事件,只能說明你看了我的文章,謝謝。