程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#基礎---事件的使用

C#基礎---事件的使用

編輯:C#入門知識

C#基礎---事件的使用


一:什麼是事件          事件是可以被控件識別的操作,如按下確定按鈕,選擇某個單選按鈕或者復選框。每一種控件有自己可以識別的事件,如窗體的加載、單擊、雙擊等事件,編輯框(文本框)的文本改變事件,等等。事件在桌面應用程序裡面無處可見,比如winform,WPF。。。,其次事件是基於委托而產生的。           二:事件的基本使用        1.事件的聲明: 其實和委托一樣只是多了一個Event而已。ShowMsg 就具備了ShowMsgHandler的功能。       Notes: 1. 委托可以依賴於一個類或者一個域名空間(C#基礎---委托的使用,裡面我有提到過), 而event必須依賴於一個類。否者無法聲明。            2. 委托可以用【=號】,而事件中只能用【+】或者【-】實現對方法的添加和刪除。當事件為空的時候調用【-】方法不會報錯。              public delegate void ShowMsgHandler(string str); public event ShowMsgHandler ShowMsg;      2.事件基本使用: 其實基本用法和委托差不多。這裡有一點要說明,其實可以通過判斷是否為Null,來確定是否已經注冊了方法到事件或者委托。這個有時候勇於判斷事件是否該觸發。其次也發現事件第一次添加方法的時候是直接使用【+】號的,而不用像委托那樣第一次使用【=】號,後面的才使用【+】號。            復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;   namespace SpongeBobCoder.EventTest {     public delegate void ShowMsgHandler(string str);     public class Program     {         public static event ShowMsgHandler ShowMsg;           public static void ShowName(string str)         {             Console.WriteLine("My Name is {0}", str);         }           public static void Main(string[] args)         {             Console.WriteLine(ShowMsg == null);             ShowMsg += ShowName;             ShowMsg("SopongeBob");             Console.WriteLine(ShowMsg == null);             Console.ReadKey();         }     } } 復制代碼           3. 為何使用事件:                其實從上面來看事件和委托差不多。用法沒啥區別,但是為何還要使用委托呢? 在Codeplex看到的一篇文檔感覺挺不錯的。http://www.codeproject.com/Articles/7316/Events-and-Delegates ;小弟英語不好,英語好的就去看看原文,我的大概理解是: 好比一個App由一個項目組在開發,必定有一個項目經理,而這個項目經理的下面會有很多幫他做事的員工,其實經理就好比是一個委托,而每一位工作的員工就好比委托注冊的方法。項目開發完成了,拿給了用戶,用戶安裝好了。可是用戶發現軟件有缺陷,需要改進,而往往這個時候用戶是不會直接跟開發組的項目經理接觸的。往往會把意見給 維護部門,而由維護部門來告知相應開發組的項目經理。而通知這段過程就叫做事件。事件可以用來更好的封裝,和管理委托的。個人理解,這就是事件為何基於特定類的。不同類的 事件可以綁定同一個委托,從而注冊不同的方法。          3.1 先什麼一個Publisher類:類中有一個事件CalculatorEvent 和一個方法DoSomething,若事件被添加方法後,那麼將執行          復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;   namespace SpongeBobCoder.EventTest {     public class Publisher     {         public event CalculatorHandler CalculatorEvent;           public void DoSomething(double num1,double num2)         {             if (CalculatorEvent != null)             {                 CalculatorEvent(num1, num2);             }         }     } } 復制代碼     3.2 然後看Program類,Main方法裡面聲明了兩個Publisher對象,分別是A,B。分別添加了AddNum和SumNum,運行結果是 3 和 -1。通過一個Publisher類可以對委托進行管理。   復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;   namespace SpongeBobCoder.EventTest {     public delegate void CalculatorHandler(double num1,double num2);       public class Program     {         public static void AddNum(double num1, double num2)         {             Console.WriteLine("兩數之和為:{0}", num1 + num2);         }           public static void SubNum(double num1, double num2)         {             Console.WriteLine("兩數之差為:{0}", num1-num2);         }           public static void Main(string[] args)         {             Publisher pubA = new Publisher();             Publisher pubB = new Publisher();             pubA.CalculatorEvent += AddNum;             pubB.CalculatorEvent += SubNum;               pubA.DoSomething(1, 2);             pubB.DoSomething(1, 2);               Console.ReadKey();         }     } } 復制代碼      三:事件的使用       1.異常處理: 事件可以注冊多個方法,可是要是其中有一個方法拋出異常了怎麼辦,一旦拋出異常了。那麼當前執行程序被中斷,那麼後面注冊的方法就沒法執行了。問題來了,那些方法可以解決這個問題呢?  方法一,保證所注冊的方法不會出現異常,這一塊我們是無法預知。 方法二。將注冊的方法的異常都吃掉,其中微軟提供了兩個方法GetInvocationList和DynamicInvoke方法:   復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;   namespace SpongeBobCoder.EventTest {     public class Publisher     {         public event CalculatorHandler CalculatorEvent;           public void DoSomething(double num1, double num2)         {             if (CalculatorEvent != null)             {                 Delegate[] delArray = CalculatorEvent.GetInvocationList(); //獲取到所有的委托方法.                 foreach (Delegate del in delArray)                 {                     try                     {                        object obj = del.DynamicInvoke(num1, num2); //obj是獲取每個方法的返回值,如果聲明的是無返回值的委托,那麼obj==null                        Console.WriteLine(obj == null);                     }                     catch (Exception e) // 把異常吃掉                     {                         Console.WriteLine(e.InnerException.Message);                      }                 }             }         }     } } 復制代碼   2.異步調用:對於前面的注冊的時間,都是順序執行,那如何實現異步執行呢,各個注冊之間不相互干擾,其實微軟提供了一個BeginInvoke方法可以解決這個問題.   Public IAsyncResult BeginInvoke (     InvokeArgs invokeArgs, // 這一部分對於的是委托     AsyncCallback callback,// 回調方法,注冊方法執行完後,將會執行回調方法     Object userState // 傳遞的參數 )             上面理解起來可能有點困難下面來看看代碼吧:             Program類: AddNum 方法有5秒的延時。SubNum沒有添加延時,注冊順序是 AddNum,SubNum   復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading;   namespace SpongeBobCoder.EventTest {     public delegate double CalculatorHandler(double num1, double num2);       public class Program     {         public static double AddNum(double num1, double num2)         {             Thread.Sleep(TimeSpan.FromSeconds(5));             Console.WriteLine("兩數之和為:{0}", num1 + num2);             return num1 + num2;         }           public static double SubNum(double num1, double num2)         {             Console.WriteLine("兩數之差為:{0}", num1 - num2);             return num1 - num2;         }             public static void Main(string[] args)         {             Publisher pubA = new Publisher();             pubA.CalculatorEvent += AddNum;             pubA.CalculatorEvent += SubNum;             pubA.DoSomething(1, 5);             Console.ReadKey();         }     } } 復制代碼     publisher類: 注意看紅色方法,前面兩個參數是與委托對應的。後面的MyCallBack是回調的方法,   復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading.Tasks;   namespace SpongeBobCoder.EventTest {     public class Publisher     {         public event CalculatorHandler CalculatorEvent;           public void DoSomething(double num1, double num2)         {             if (CalculatorEvent != null)             {                 Delegate[] delArray = CalculatorEvent.GetInvocationList(); //獲取到所有的委托方法.                 foreach (Delegate del in delArray)                 {                     try                     {                         CalculatorHandler handler = del as CalculatorHandler;                         IAsyncResult myResult = handler.BeginInvoke(num1, num2, MyCallback, "方法執行完畢,回調成功" + handler.Method.Name);                         // Console.WriteLine("SpongeBob"); 這塊代碼不注釋的話是先執行這段代碼的輸出,然後才會輸出其他的。這一塊我不知道為什麼                     }                     catch (Exception e) // 把異常吃掉                     {                         Console.WriteLine(e.InnerException.Message);                     }                 }             }         }           public void MyCallback(IAsyncResult asyncResult)         {             AsyncResult result = (AsyncResult)asyncResult;             CalculatorHandler handler = (CalculatorHandler)result.AsyncDelegate;             Console.WriteLine(asyncResult.AsyncState);             Console.WriteLine("獲取到執行結果為:{0} \n", handler.EndInvoke(asyncResult));         }     } } 復制代碼         運行結果: 其實先執行的是 SubNum,已經達到了異步的效果,其中通過EndInvoke也在回調函數中獲取到了委托的返回值。                codezip:http://files.cnblogs.com/FourLeafCloverZc/CSharp.zip   總結:  以前最開始的對事件理解不清楚,記得當時在winform的時候跨線程獲取數據就要用Invoke來獲取,不然老是提示線程不安全。本次博客中我發現了兩個問題需要個各位博友幫忙解答    1. 在異步調用的代碼中有一段代碼被我注解了。其實我發現了一個問題, 如果 Console.WriteLine("SpongeBob"); 不注解,運行的情況是,先輸出兩行(“SpongeBob”) 然後再輸出 上圖的運行結果。不清楚是什麼原因,求大神指點。    2. 對於下面代碼如果調用的傳入的參數是1,0 ; 是不會報錯的。運行結果是兩數相除無窮大。應該會報除數不能為0的異常呀。           public static void DivNum(double num1, double num2)         {             Console.WriteLine("兩數相除為:{0}", num1 / num2);         }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved