Events

advertisement
Высокоуровневые методы
информатики и
программирования
Лекция 10
События
План работы
•
•
•
•
что такое и для чего используются
как создаются
как инициируются
как обрабатываются
Работа с событиями в C#
• С помощью делегатов в классах можно описывать
события.
• События это способ взаимодействия между объектами
разных классов.
– Объекты одного класса могут использовать объекты других
классов.
– Для этого они создают объекты требуемого класса и
вызывают его методы (передают ему сообщения).
– При работе вызванных методов часто возникает
необходимость передать сообщения о возникших ситуациях
(важных изменения в своей работе) объектам вызывающего
класса, без завершения их работы.
– Для передачи таких сообщений и используются
специальные элементы класса – события.
События
Сообщение объекта своему пользователю о том,
что произошло что-то важное.
Например:
• Выполнена какая-то часть работы
• Произошла ошибка
• Пользователь выполнил некоторые действия (переместил
мышь, сделал щелчок, нажал клавишу)
Вся работа программ с среде ОС Windows основана
на событиях
Программирование основанное на событиях – event
driven programming.
События (2)
• Обычно класс пользователь (client) вызывает
методы используемого класса (server)
• События позволяют используемому классу
вызывать методы пользовательского класса
Вызов методов
Сервер
Клиент
Пользовательский
класс
Используемый класс
Сообщения о событиях
События (3)
Метод, использующий MyClass
MyClass a;
public void MySub()
{
a = new OtherClass
a.SomeEvent += MyHandle;
…
a.metod(); // вызываем метод с событиями
…
}
Обработчик события
void MyHandle(object o, int d)
public delegate Handler(…);
public event Handler SomeEvent;
Метод класса MyClass с
событием SomeEvent:
Метод: method()
Произошло что-то важное
SomeEvent(this, data)
Вызов обработчика
события
Возврат управления
{
...
}
Проблема: как объект узнает о том,
какую функцию у пользователя
вызывать ???
Добавление события в класс
1. Создать открытую переменную, которая
может хранить ссылки.
2. Когда возникнет нужное событие, то
вызвать все методы, ссылки на которые
этой переменной будут присвоены.
Объявление события в классе
•
Вначале объявляется делегат, как это рассматривалось ранее. Объявление делегата
описывается в некотором классе. Но, часто, это объявление находится вне класса в
пространстве имен.
public delegate <тип> <имя_делегата> ([параметры]);
–
Например:
public delegate void MyHandler (object o, int n);
•
Объявить событие как экземпляр соответствующего делегата. При этом используется
ключевое слово event (это гарантирует, что экземпляр события не может быть вызван в
других классах).
рublic event <имя_делегата> <имя_события>;
–
•
Например:
public event MyHandler MyEvent;
Для инициирования события требуется просто вызвать на выполнение экземпляр делегата.
–
Например:
if (MyEvent != null) // проверка, что для события заданы обработчики
MyEvent(this, i); // если есть обработчики, то запускаем событие
Сигнатура обработчика события
• В FCL все обработчики имеют два
параметра
public delegate void MyChangeHandler
(MyObject o, MyEventArgs i);
– EventArgs – базовый класс для всех классов
передачи данных о событии
– class MyEventArgs : EventArgs { . . . }
Объявление и инициирование
события класса
• Объявления делегата
// делегат, который должны реализовать подписчики
public delegate void Handler (object o, EventArgs ea);
// объявление событий event
public event Handler OnChange;
public event Handler OnClick;
public event Handler OnMove;
Ключевое слово event
Ключевое слово event указывает компилятору,
что делегат может вызываться
описывающим классом, и что другие
классы могут только подписываться и
отписываться от делегата используя
соответствующие += и -=.
Пример описания события
// Объявление нового типа – делегата
public delegate void MyHandler (object o, int n);
// объявление класса с событием
public class ClassWithEvent { // класс с событием
// Создание экземпляра делегата - событие
public event MyHandler MyEvent;
// поле класса
private int Volume = 0;
// конструктор класса – парамер – объем работы
public EventClass(int p){if (p > 0) Volume = p;}
//описание метода выполняющего долгую работу (в данном примере бессмысленную)
public void LongWork(){
double s = 0; int k = 0;
int st = Volume / 10; // десятая часть работы
for (int i = 0; i < Volume; i++) {
s += Math.Atan(Math.Sqrt(i) * Math.Sqrt(i));
if (k == st) {// выполнена заданная часть работы
if (MyEvent != null){
int n = (int)(i*100.0)/Volume;
MyEvent(this, n); // запускаем событие
}
k = 0;
}
else k += 1;
}}}
Обработка событий в классах
В классе, который будет обрабатывать
событие, нужно:
1. описать метод - обработчик события,
который имеет такую же сигнатуру, как у
делегата, который задает событие;
2. в одном из методов создать объект,
имеющий событие;
3. присвоить ссылку на метод – обработчик
события – открытой переменной объекта
(событию) с использованием операции +=.
Пример обработки события
class Program {
const int WorkVolume = 10000000; // объем работы
// обработчик события
private static void ShowStar(object o, int n)
{
Console.WriteLine(" Выполнено {0}%", n);
//Console.Write("*"); // можно просто выводить *
}
public static void Main()
{
// создается объект
ClassWithEvent obj=new ClassWithEvent(WorkVolume);
// событию задается обработчик
obj.MyEvent += new MyHandler(ShowStar);
// запускам метод объекта у которого возникает данное событие
obj.LongWork();
// ждем нажатия клавиши
Console.ReadLine();
}
}
Подписка и отписка на событие
•
Создание метода, который имеет такую же сигнатуру, что и обработчик
события – Handler
void f (….);
• Создать экземпляр делегата
Handler a = new Handler (func);
• Подписаться на событие (obj – объект у которого есть событие)
obj.OnChange += a;
• Отписаться от события (obj – объект у которого есть событие)
obj.OnChange -= a;
Или
• Подписаться на событие
obj.OnChange += new Handler (func);
• Отписаться от события
obj.OnChange -= new Handler (func);
Download