Содержание

Слайд 2

имя _события - идентификатор, выбираемый программистом в качестве названия конкретного члена,

имя _события - идентификатор, выбираемый программистом в качестве названия конкретного члена,

называемого переменной события.
имя_делегата – имя делегата-типа(событийный делегат). Он должен представлять событию те методы, которые будут вызываться в ответ на посылку сообщения о событии.
Cобытие – это член класса, имеющий тип делегата.
Пример
Определить статический метод, посылающий через каждую секунду сообщение о событии.
В рассмотренном примере делегат объявлен вне классов и все методы статические. Таким образом, с помощью механизма событий взаимодействуют не объекты, а методы одного класса.
Слайд 3

В технологии Windows – программирования принято говорить, что объект (в данном

В технологии Windows – программирования принято говорить, что объект (в данном

примере статический метод класса) публикует события, посылая сообщения о них. Другие объекты ( в данном примере – статические методы) могут подписаться на них.
Подписка на получение сообщений о событии в языке C# предусматривает следующие действия:
создание экземпляра того делегата, на который настроено событие;
подключение экземпляра делегата к событию.
Обычно эти два действия объединяют в одном операторе следующего формата:
имя_события += new имя делегата(имя метода);
Условие применимости подписки на событие – наличие и доступность метода, который будет вызван для обработки события.
Имя этого метода используется в качестве аргумента конструктора делегата. На одно событие могут быть подписаны несколько методов, для каждого из которых нужно использовать свой оператор приведенного вида.
Слайд 4

using System; delegate void TimeHandler(); class Test_cs { static event TimeHandler

using System;
delegate void TimeHandler();
class Test_cs {
static event TimeHandler onTime;
static

void run()
{
Console.WriteLine("exit ctrl + c");
while (true)
onTime();
System.Threading.Thread.Sleep(1000);
}
Примечание:
Sleep() –статический метод класса Thread из пространства имен System.Threading
Слайд 5

class Program { static void Main(string[] args) { onTime += new

class Program
{
static void Main(string[] args)
{
onTime += new

TimeHandler(one);
onTime += new TimeHandler(two);
run();
}
static void one() {
string newTime = DateTime.Now.ToString();
Console.Write("\t\t\t{0}", newTime);
}
static int count = 0;
static void two() {
Console.Write("\r{0}", count++);
}
}
}
Слайд 6

Более общий случай – событие создается объектом, а в других объектах

Более общий случай – событие создается объектом, а в других объектах

( в объектах других классов) имеется возможность реагировать на эти события.
using System;
//объявление делегата для события
delegate void MyEventHandler();
//объявление класса события
class MyEvent
{
public event MyEventHandler SomeEvent;//объект
// вызывается для генерации события
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent();
}
}
Слайд 7

class EventDemo { // обработчик события static void Handler() { Console.WriteLine("

class EventDemo
{
// обработчик события
static void Handler()
{

Console.WriteLine(" событие произошло");
}
public static void Main(string[] args)
{
MyEvent evt = new MyEvent();
// добавление Handler() в список обработчиков
evt.SomeEvent += Handler; //преобразование метода в делегат
//генерация события
evt.OnSomeEvent();
}
}
Слайд 8

Пример множественной адресации события Как и делегаты, события могут быть многоадресными.

Пример множественной адресации события
Как и делегаты, события могут быть многоадресными. Благодаря

использованию множественной адресации на извещение о наступлении события может отвечать несколько объектов.
Пример
using System;
delegate void MyEventHandler();
class MyEvent {
public event MyEventHandler SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent();
}
}
Слайд 9

class X { public void XHandler() { Console.WriteLine("Событие, получаемое объектом Х");

class X {
public void XHandler()
{
Console.WriteLine("Событие, получаемое объектом Х");

}
}
class Y {
public void YHandler()
{
Console.WriteLine("Событие, получаемое объектом Y");
}
}
Слайд 10

class EventDemo { static void Handler() { Console.WriteLine("Событие, получаемое EventDemo"); }

class EventDemo {
static void Handler()
{
Console.WriteLine("Событие, получаемое EventDemo");
}

static void Main(string[] args)
{
MyEvent evt = new MyEvent();
X xOb = new X();
Y yOb = new Y();
// Добавление обработчиков события
evt.SomeEvent += Handler;
evt.SomeEvent += xOb.XHandler;
evt.SomeEvent += yOb.YHandler;
// Генерация события
evt.OnSomeEvent();
Console.WriteLine();
//удаление обработчика
evt.SomeEvent -= xOb.XHandler;
evt.OnSomeEvent();
}
}
Слайд 11

Результат выполнения программы Событие, получаемое EventDemo Событие, получаемое объектом X Событие,

Результат выполнения программы
Событие, получаемое EventDemo
Событие, получаемое объектом X
Событие, получаемое объектом Y
Событие,

получаемое EventDemo
Событие, получаемое объектом Y
Слайд 12

Итак, имя делегата обычно состоит из названия события и слова EventHandler.


Итак, имя делегата обычно состоит из названия события и слова EventHandler.
Например:
public

delegate ChangedEventHandler(object sender, ChangedEventArgs args)
sender – объект, создавший событие
аrgs – содержащий связанные с событием параметры.
Слайд 13

Любое событие – это на самом деле набор двух скрытых методов,

Любое событие – это на самом деле набор двух скрытых методов,

определенных как public. Один из методов начинается с приставки add_, а второй – с приставки remove_.
Например, событие SomeEvent отображается в следующие методы:
//Это событие отображается в скрытые методы
//add_ SomeEvent() и
//remove_ SomeEvent()
public event MyEventHandler SomeEvent;
Помимо скрытых методов add_XXXX() и remove_XXXX() , каждому событию также соответствует статический класс, определенный как private. Его назначение – привязывать событие к соответствующему делегату. При этом при срабатывании события будет вызван каждый из методов делегата. Такой способ позволяет сразу нескольким «приемникам» событий получать одно – единственное происшедшее событие.
Слайд 14

Использование аксессоров событий Существует две формы блока кода event. Первая форма

Использование аксессоров событий
Существует две формы блока кода event.
Первая форма позволяет создавать

события, которые автоматически управляют списком вызова обработчиков, включая добавление обработчиков в список и удаление обработчиков из списка. Таким образом, не требуется реализовывать функциональность управления этим списком.
Вторая форма блока кода event дает возможность управлять списком обработчика событий программисту. Данная форма позволяет использовать аксессоры событий.
Аксессорная форма блока кода event имеет следующий вид:
event делегат_ события имя_события
{
add
{
// код добавления события в цепочку событий
}
remove
{
// код удаления события из цепочки событий
}
}
Аксессор add вызывается тогда, когда в цепочку добавляется обработчик события с помощью оператора +=, а аксессор remove вызывается, когда из цепочки событий удаляется обработчик события с помощью оператора -=.
Слайд 15

Механизм работы с событиями предусматривает несколько этапов. Объявление делегата – типа,

Механизм работы с событиями предусматривает несколько этапов.
Объявление делегата – типа, задающего

сигнатуру тех (еще неизвестных на данном этапе) методов, которые будут вызываться при обработке события.(1)
Определение переменной события, имеющей тип делегата события.(2)
Определение генератора события (посылки сообщения), с указанием аргументов, информирующих получателей о состоянии объекта, пославшего сообщение.(3)
Определение методов обработки события. Сигнатура каждого метода должна соответствовать типу делегата события.(4)
Создание экземпляра того делегата, на который “настроено” событие. Аргумент конструктора – имя метода обработки.(5)
Подключение экземпляра делегата к переменной события.(6)
Класс, обрабатывающий события, должен содержать методы обработки или, по крайней мере, иметь доступ к этим методам. В нем реализуются этапы 4, 5, 6.
Второй класс – это класс, генерирующий события, реализует этапы 1, 2, 3.
Зачастую в программе присутствует третий класс, управляющий процессом на более высоком уровне. Его называют супервизором, монитором, диспетчером.
Слайд 16

При наличии такого класса и двух подчиненных – класса генерации и

При наличии такого класса и двух подчиненных – класса генерации и

класса обработки событий – схема работы супервизора сводится к следующим шагам.
Создать объект класса генерации событий.
Создать класс обработки событий (может не потребоваться, если метод обработки является статическим).
Создать экземпляр делегата, “настроив” его на метод класса обработки событий.
Подключить экземпляр делегата к переменной события из объекта класса генерации.
Передать управление объекту класса генерации событий( какому – либо из методов, генерирующих события).
Далее все управляется в соответствии с общими принципами событийного управления.
Слайд 17

Пример. Рассмотрим программу с делегатом и четырьмя классами. Класс Sorting содержит

Пример.
Рассмотрим программу с делегатом и четырьмя классами.
Класс Sorting содержит метод,

который сортирует в порядке возрастания одномерный целочисленный массив.
Класс View содержит метод обработки события. Метод выводит на консоль значение счетчика перестановок.
Класс Display визуализирует динамику процесса сортировки – выводит на консоль имитацию элемента управления ProgressBar.
Класс Controller (управляющий). Метод Main() в соответствии с общей схемой создает объект класса, генерирующего события, объект класса – обработчика(View). Затем подключает к переменной события два наблюдателя – два безымянных экземпляра делегата SortHandler.И, наконец, управление передается методу сортировки объекта – генератора событий.
Слайд 18

using System; public delegate void SortHandler(long cn, int si, int ki);

using System;
public delegate void SortHandler(long cn, int si, int ki);
class Sorting
{

int size;
int[] ar;
public long count;
public event SortHandler onSort;
public Sorting(int[] ls)
{
size = ls.Length;
count = 0;
ar = ls;
}
Слайд 19

public void sort() { int temp; for(int i = 0; i

public void sort()
{
int temp;
for(int i = 0; i

1; i++)
{
for(int j = i+1;j < size; j++)
if (ar[i] > ar[j])
{
temp = ar[i];
ar[i] = ar[j];
ar[j] = temp;
count++;
}
if (onSort != null)
onSort(count,size,i);
}
}
}
class View
{
public void nShow(long n, int si, int ki)
{
Console.Write("\t" + n);
}
}
Слайд 20

class Display { static int len = 30; static string st

class Display
{
static int len = 30;
static string st =

null;
public static void barShow(long n, int si, int ki)
{
int pos = Math.Abs((int)((double) ki / si * len));
string s1 = new string('\u258c',pos);
string s2 = new string('-',len - pos - 1) + '\u25c4';
st = s1 + '\u258c' + s2;
Console.Write("\r\t\t" + st);
}
}
class Controller
{
static void Main(string[] args)
{
Random ran = new Random(55);
int [] ar = new int[19999];
for(int i = 0;i < ar.Length;i++)
ar[i] = ran.Next();
Sorting run = new Sorting(ar);
View watch = new View();
run.onSort += new SortHandler(Display.barShow);
run.sort();
Console.Write("\n");
}
}
Слайд 21

Событийный делегат SortHandler и переменная события onSort должны быть одинаково доступны

Событийный делегат SortHandler и переменная события onSort должны быть одинаково доступны

в месте подписки на событие.
При генерации события целесообразно проверять значение переменной события. Эта переменная остается равной null, если на событие нет ни одной подписки.
Обратите внимание на тот факт, что генерация события в отличие от генерации исключения оформляется как обращение к методу. Тем самым после обработки события управление автоматически возвращается в точку, непосредственно следующую за оператором генерации события.
Слайд 22

Различные возможности использования событий События могут быть определены в интерфейсах. В

Различные возможности использования событий
События могут быть определены в интерфейсах.
В этом случае

реализующие классы должны обеспечивать реализацию конкретных событий.
События можно определять как абстрактные. Реализацию такого события должен обеспечивать производный класс.
Но, события, объявленные с использованием аксессоров, не могут быть абстрактными.
Событие можно определить как sealed.
Событие может быть виртуальным, т.е. его можно переопределить в производном классе.
Слайд 23

Использование анонимных методов с событиями Анонимный метод можно использовать в качестве

Использование анонимных методов с событиями
Анонимный метод можно использовать в качестве обработчика

события, что позволяет обойтись без объявления отдельного метода, а это в свою очередь позволяет значительно сократить код реализации механизма обработки события.
Слайд 24

using System; namespace AnonimDemo { delegate void MyEventHandler(); class MyEvent {

using System;
namespace AnonimDemo
{
delegate void MyEventHandler();
class MyEvent
{
public event

MyEventHandler SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent();
}
}
}
class AnonMethHandler
{
public static void Main()
{
MyEvent evt = new MyEvent();
//анонимный метод как обработчик события
evt.SomeEvent += delegate
{
// блок обработки события
Console.WriteLine("Событие получено");
};
evt.OnSomeEvent();
}
}
}
Слайд 25

using System; using System.Collections; namespace EventDemo { public delegate void ChangedEventHandler(object

using System;
using System.Collections;
namespace EventDemo
{
public delegate void ChangedEventHandler(object sender,
ChangedEventArgs EventArgs);
public

class ChangedEventArgs:EventArgs
{
private object item;
private bool permit;
public object Item
{
get {return (item);}
set {item = value;}
}
public bool Permit
{
get { return(permit);}
set { permit = value;}
}
Слайд 26

public class ListWithChangedEvent:ArrayList { public event ChangedEventHandler Changed; private ChangedEventArgs evargs

public class ListWithChangedEvent:ArrayList
{
public event ChangedEventHandler Changed;
private ChangedEventArgs evargs

= new ChangedEventArgs();
protected virtual void OnChanged(ChangedEventArgs args)
{
if (Changed != null)
Changed(this, args);
}
public override int Add(object value)
{
int i = 0;
evargs.Item = value;
OnChanged(evargs);
if (evargs.Permit) i = base.Add(value);
else Console.WriteLine(" добавление элемента запрещено" +
"Значение = {0}", value);
return i;
}
Слайд 27

public override void Clear() { evargs.Item = 0; OnChanged(evargs); base.Clear(); }

public override void Clear()
{
evargs.Item = 0;
OnChanged(evargs);
base.Clear();
}

public override object this[int index]
{
set{
evargs.Item = value;
OnChanged(evargs);
if (evargs.Permit)
base[index] = value;
else Console.WriteLine
( "Замена элемента запрещена"
+ "Значение = {0}", value);
}
get{return (base[index]);}
}
Слайд 28

public class EventReceiver1 { private ListWithChangedEvent List; public EventReceiver1(ListWithChangedEvent list) {

public class EventReceiver1
{
private ListWithChangedEvent List;
public EventReceiver1(ListWithChangedEvent list)
{

List = list;
OnConnect();
}
private void ListChanged(object sender, ChangedEventArgs
args)
{
Console.WriteLine(
" EventReceiverl: сообщаю об изменениях:"
+ "Item = {0}", args.Item);
args.Permit = ((int)args.Item < 10);
}
public void OnConnect()
{
List.Changed += new ChangedEventHandler
(ListChanged);
}
}
Слайд 29

class EventReceiver2 { private ListWithChangedEvent List; public EventReceiver2(ListWithChangedEvent list) { List

class EventReceiver2
{
private ListWithChangedEvent List;
public EventReceiver2(ListWithChangedEvent list)
{
List

= list;
OnConnect();
}
private void ListChanged(object sender,
ChangedEventArgs args)
{
Console.WriteLine("Receiver2:сообщаю об изменениях:"
+ "объект класса {0}: Item = {1}",
sender.GetType(), args.Item);
args.Permit = ((int)args.Item < 20);
}
public void OnConnect()
{
List.Changed += new ChangedEventHandler(ListChanged);
}
}