Cобытия
События События представляют собой механизм, посредством которого объект имеет возможность получать информацию о происходящем вне него. Объявление события: event EventHandler anEvent; Класс, решивший иметь события, должен уметь, по крайней мере, три вещи: объявить событие в классе; зажечь в нужный момент событие, передав обработчику необходимые для обработки аргументы. (Под зажиганием или включением события понимается некоторый механизм, позволяющий объекту уведомить клиентов класса, что у него произошло событие.); проанализировать, при необходимости, результаты события, используя значения выходных аргументов события, возвращенные обработчиком.
Делегаты и события. Класс Sender [атрибуты] [модификаторы]event [тип, заданный делегатом] [имя события] Объявляется делегат - функциональный класс, задающий сигнатуру. Объявляется событие как экземпляр соответствующего делегата. namespace Events{ public delegate void FireEventHandler(object Sender, int time, int build); public class TownWithEvents{ public event FireEventHandler FireEvent;... }... }
Зажигание события. Класс Sender protected virtual void OnFire(int time, int build){ if (FireEvent!=null) FireEvent(this,time, build); }
Как обрабатываются события. Классы Receiver. Класс Receiver должен: иметь обработчик события - процедуру, согласованную по сигнатуре с функциональным типом делегата, который задает событие; иметь ссылку на объект, создающий событие, чтобы получить доступ к этому событию - event- объекту; уметь присоединить обработчик события к event- объекту.
public class FireMen{ //создание ссылки на объект, создающий событие private TownWithEvents MyTown; public FireMen(TownWithEvents TWE) { this.MyTown=TWE; //присоединение обработчика события к объекту событие MyTown.FireEvent += new FireEventHandler(FireHandler); } private void FireHandler(object Sender, int time, int build) { //процедура обработчика события Console.WriteLine("Fire at day {0}, in build {1}!", time, build); } public void GoOut() { //отключение обработчика события от объекта событие MyTown.FireEvent -= new FireEventHandler(FireHandler); }
Классы с событиями, допустимые в каркасе.Net Framework delegate (object sender, EventArgs args); Две проблемы с обработчиками событий: Игнорирование коллег Переопределение значений аргументов события
Схема «зажигания» и обработки события public delegate void MyEventHandler(object Sender, MyEventArgs e); public class Sender { public event MyEventHandler mEvent; public void OnEvent() { MyEventArgs e = new MyEventArgs(); if(mEvent!=null) mEvent(this, e); } ….. } public class Receiver { private Sender s; public Receiver (Sender s) { this.s = s ; s.mEvent += new MyEventHandler(MyHandler); } private void MyHandler(object Sender, MyEventArgs e) { //процедура обработчика события } …. }
Классы с большим числом событий using System.Collections; class ManyEvents{ //хэш таблица для хранения делегатов Hashtable DStore = new Hashtable(); public event EventHandler Ev1 { add { DStore["Ev1"]= (EventHandler)DStore["Ev1"]+ value; } remove { DStore["Ev1"]= (EventHandler)DStore["Ev1"]- value; } public event EventHandler Ev2 { add { DStore["Ev2"]= (EventHandler)DStore["Ev2"]+ value; } remove { DStore["Ev2"]= (EventHandler)DStore["Ev2"]- value; } …… public void SimulateEvs() { EventHandler ev; ev = (EventHandler) DStore["Ev1"]; if(ev != null) ev(this, null); ev = (EventHandler) DStore["Ev2"]; if(ev != null) ev(this, null); }
class ReceiverEvs{ private ManyEvents manyEvs; public ReceiverEvs( ManyEvents manyEvs) { this.manyEvs = manyEvs; OnConnect(); } public void OnConnect() { manyEvs.Ev1 += new EventHandler(H1); manyEvs.Ev2 += new EventHandler(H2); } public void H1(object s, EventArgs e) { Console.WriteLine("Событие Ev1"); } public void H2(object s, EventArgs e) { Console.WriteLine("Событие Ev2"); } public void TestManyEvents(){ ManyEvents me = new ManyEvents(); ReceiverEvs revs = new ReceiverEvs(me); me.SimulateEvs(); }
Проект "Город и его службы" public delegate void FireEventHandler(object sender, FireEventArgs args); public class NewTown{ private int build, BuildNum; private int day, days; //городские службы private Police policeman ; private Ambulance ambulanceman ; private FireDetect fireman ; public event FireEventHandler Fire; //моделирование случайных событий private Random rnd = new Random(); private int m = 3, n= 10000; public NewTown(int TSize, int Days){ BuildingNum = rnd.Next(TSize); days = Days; policeman = new Police(this); ambulanceman= new Ambulance(this); fireman= new FireDetect(this); policeman.On(); ambulanceman.On(); fireman.On(); } protected virtual void OnFire(FireEventArgs e){ if(Fire != null) Fire(this, e); } public void LifeOurTown(){ for(day = 1; day
Городские службы public abstract class Receiver { private NewTown town; public Receiver(NewTown town) { this.town = town;} public void On() { town.Fire += new FireEventHandler(It_is_Fire); } public void Off() { town.Fire -= new FireEventHandler(It_is_Fire); town = null; } public abstract void It_is_Fire (object sender, FireEventArgs e); } public class Police : Receiver { public Police (NewTown town): base(town){} public override void It_is_Fire(object sender, FireEventArgs e){ Console.WriteLine("Пожар в доме {0}. День {1}-й. Милиция ищет виновных!", e.Build,e.Day); e.Permit &= true; } } public class FireDetect : Receiver { public FireDetect (NewTown town): base(town){} public override void It_is_Fire(object sender, FireEventArgs e) { Console.WriteLine("Пожар в доме {0}. День {1}-й. Пожарные тушат пожар!", e.Build,e.Day); Random rnd = new Random(e.Build); if(rnd.Next(10) >5) e.Permit &= false; else e.Permit &=true; } } public class Ambulance : Receiver { public Ambulance(NewTown town): base(town){} public override void It_is_Fire(object sender, FireEventArgs e) { Console.WriteLine("Пожар в доме {0}. День {1}-й. Скорая спасает пострадавших!", e.Build,e.Day); e.Permit &= true; } }
Тестирование public class FireEventArgs : EventArgs{ private int build; private int day; private bool permit; public int Build { get{ return(build);} } public int Day { get{ return(day);} } public bool Permit { get{ return(permit);} set{ permit = value;} } public FireEventArgs(int build, int day, bool permit) { this.build = build; this.day = day; this.permit = permit; } public void TestLifeTown(){ NewTown smtown = new NewTown(100,100); smtown.LifeOurTown(); }