關於c#的事件如何使用
事件是C#中另一高階概念,使用方法和委託相關。奧運會參加百米的田徑運動員聽到槍聲,比賽立即進行。其中槍聲是事件,而運動員比賽就是這個事件發生後的動作。不參加該項比賽的人對槍聲沒有反應。
從程式設計師的角度分析,當裁判員槍聲響起,發生了一個事件,裁判員通知該事件發生,參加比賽的運動員仔細聽槍聲是否發生。運動員是該事件的訂閱者,沒有參賽的人不會注意,即沒有訂閱該事件。
C#中使用事件需要的步驟:
1、建立一個委託;
2、將建立的委託與特定事件關聯(.Net類庫中的很多事件都是已經定製好的,所以他們也就有相應的一個委託,在編寫關聯C#事件處理程式--也就是當有事件發生時我們要執行的方法的時候我們需要和這個委託有相同的簽名);
3、編寫C#事件處理程式;
4、利用編寫的C#事件處理程式生成一個委託例項;
5、把這個委託例項新增到產生事件物件的事件列表中去,這個過程又叫訂閱事件。
一、定義事件
定義事件時,發生者首先要定義委託,然後根據委託定義事件。定義事件的語法如下:
<訪問修飾符> event 委託名 事件名;
定義事件時,一定要有一個委託型別,用這個委託型別來定義處理事件的方法型別。下面定義一個釋出者類,並在其內部定義eventRun事件。
class Judgment
{
//定義一個委託
public delegate void delegateRun();
//定義一個事件
public event delegateRun eventRun;
}
二、訂閱事件
定義好事件後,與事件有關的人會訂閱事件,只有訂閱事件的物件才會收到發生事件的通知,沒有訂閱該事件的物件則不會收到通知。訂閱事件的語法如下:
事件名+=new 委託名(方法名);
假如方法名為Run,那麼訂閱事件eventRun的程式碼如下:
judgment.eventRun+=new Judgment.delegateRun(runsport.Run);
judgment為類Judgment的物件,runsport為運動員類RunSports的物件,Run為其中的方法。
事件的訂閱通過“+=”操作符來實現,可以給事件加一個或多個方法委託。
三、引發事件
一般都是在滿足某個條件下引發事件,裁判員槍聲一響,引發運動員奔跑這個事件。在程式設計中可以用條件詰句,也可以使用方法引發事件。
public void Begin() { enentRun(); }
這段程式碼中,通過Begin方法引發事件enentRun。引發事件的語法與呼叫方法的語法相同,引發該事件時,將呼叫訂閱事件的物件的所有委託。下面程式碼演示裁判員槍聲響起到引發運動員比賽的動作,完整程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example_EventTest
{
class Judgment
{
//定義一個委託
public delegate void delegateRun();
//定義一個事件
public event delegateRun eventRun;
//引發事件的方法
public void Begin()
{
eventRun();//被引發的事件
}
}
class RunSports
{
//定義事件處理方法
public void Run()
{
Console.WriteLine("運動員開始比賽");
}
}
class Program
{
static void Main(string[] args)
{
RunSports runsport = new RunSports();//例項化事件釋出者
Judgment judgment = new Judgment();//例項化事件訂閱者
//訂閱事件
judgment.eventRun+=new Judgment.delegateRun(runsport.Run);
//引發事件
judgment.Begin();
Console.ReadKey();
}
}
}
Judgment類為事件釋出者,RunSports類為事件訂閱者。引發事件的方法為Begin();。一個事件可以有多個訂閱者,事件的釋出者也可以是事件的訂閱者。
================================================================================================
一、無引數,無返回的委託事件
委託事件類、事件的發生源。1.宣告委託 2定義事件 3具體方法
public class Test
{
// ….
public delegate void TestHandler();//無引數,無返回委託
public event TestHandler TestEvent;//事件
public void OnTestHandler()//呼叫
{
if(TestEvent != null) //不等於null 說明該事件已經註冊有函式
{
this.TestEvent();
}
}
}
呼叫觸發事件方法(這裡把註冊和呼叫寫在一起,實際可以把註冊寫在另外的類)
class Program
{
static void Main(string[] args)
{
Test model = new Test();//實列
model.TestEvent += model_TestEvent;//為model 註冊TestEvent事件的執行方法
model.OnTestHandler();//呼叫引發事件
}
static void model_TestEvent()//事件執行方法,該方法樣式要與委託一致(引數,返回值)
{
Console.WriteLine("這是最簡單的事件");
}
}
補充1、委託鏈。通過+= 新增執行函式。
model.TestEvent += model_TestEvent;//為model 註冊TestEvent事件的執行方法,符合TestHandler委託樣式(引數,返回值)的方法都可以進行註冊,可註冊多個函式,按順序執行。如改為
model.TestEvent += model_TestEvent1;
//model.TestEvent += new Test.TestHandler(model_TestEvent1);也可以這樣寫
model.TestEvent += model_TestEvent2;
static void model_TestEvent1()
{
Console.WriteLine("這是事件的函式1");
}//可設定斷點看執行順序
static void model_TestEvent2()
{
Console.WriteLine("這是事件的函式2");
}
補充2、委託事件 結合在釋出訂閱者模式中。
Main(string[] args)方法中我們進行了註冊和呼叫,像觀察者模式使用,就會把註冊和呼叫進行分開。
註冊類,也就是所謂的訂閱類。該類也可以寫成介面,給不同業務的監聽者用來繼承擴張,這裡所有監聽者都執行model_TestEvent()函式。
public class Listeners
{
//註冊
public void registerEvent(Test model)
{
model.TestEvent += newTest.TestHandler(model_TestEvent);
}
//登出
public void nullifyEvent(Test model)
{
model.TestEvent -= newTest.TestHandler(model_TestEvent);
}
public virtual void model_TestEvent()
{
Console.WriteLine("這是所有監聽者要執行的函式");
}
}
這裡原來是註冊事件,現在改為例項,註冊監聽者。
static void Main(string[] args)
{
Test model = new Test();
//可以例項註冊多個監聽者
Listeners listener1 = new Listeners();
Listeners listener2 = new Listeners();
listener1.registerEvent(model);
listener2.registerEvent(model);
model.OnTestHandler(); //事件觸發後,會向所有註冊的監聽者傳送,所有監聽者執行函式model_TestEvent
}
二、帶引數、返回值的委託事件
首先定義事件的引數,這是自定義事件傳入的引數,從Eventargs繼承,也可直接用Eventargs,這裡為了簡單就只給了個string欄位,利用建構函式賦值。
一般帶返回的委託事件,不會採用+=,因為委託鏈的話,非void,會忽略前面的函式,只會返回最後一個函式的結果。
public class TestEventArgs : EventArgs
{
public string parameters;
public TestEventArgs(string par)
{
parameters = par;
}
}
委託事件類
public class Test
{
public delegate string TestHandler(object sender, TestEventArgs tea);//帶引數,帶返回的委託
public event TestHandler TestEvent; //定義事件
public string OnTestEvent(TestEventArgs tea)//呼叫
{
if (TestEvent != null)
{
return TestEvent(this,tea);
}
return null;
}
}
註冊觸發
static void Main(string[] args)
{
Test model = new Test();
model.TestEvent += model_TestEvent;//註冊事件
TestEventArgs tea = new TestEventArgs("test");//事件傳入引數
string result= model.OnTestEvent(tea) ;//事件觸發,得到結果
Console.WriteLine(result);
}
static string model_TestEvent(object sender, TestEventArgs tea)
{
return "傳入的引數是:" +tea.parameters ;
}
補充1、
這裡註冊和觸發同樣可以分開,前面的註冊類中把model_TestEvent改為
public virtual string model_TestEvent(objectsender,TestEventArgs tea)//事件執行函式
{
return "傳入的引數是:" +tea.parameters;
}
class Program
{
static void Main(string[] args)
{
Test model = new Test();//例項
Listeners listener = new Listeners();//例項監聽
listener.registerEvent(model);//註冊
TestEventArgs tea = new TestEventArgs("test"); //事件引數
string result= model.OnTestEvent(tea);
Console.WriteLine(result);
}
}
補充2、
事件引數型別也可以封裝,放在Test類內(OnTestEvent改為privte)。在Test類內加多
public string InitEvent(string par)
{
TestEventArgs tea = new TestEventArgs(par);
return OnTestEvent(tea);
}
Main就可以改為
static void Main(string[] args)
{
Test model = new Test();
Listeners listener = new Listeners();
listener.registerEvent(model);//監聽者註冊到Test.這裡如果很多不同業務的監聽者的話,如何返回所有監聽者處理完的資訊。修改Listeners類?(單例,管理者類)。
string result = model.InitEvent("test");
Console.WriteLine(result);
}