События (events) События позволяют классу или объекту уведомлять другие классы или объекты о возникновении каких-либо ситуаций. Событие представляет собой.

Презентация:



Advertisements
Похожие презентации
События (events) События позволяют классу или объекту уведомлять другие классы или объекты о возникновении каких-либо ситуаций. Событие представляет собой.
Advertisements

©Павловская Т.А. (СПбГУ ИТМО) Курс «С#. Программирование на языке высокого уровня» Павловская Т.А.
Высокоуровневые методы информатики и программирования Лекция 10 События.
Высокоуровневые методы информатики и программирования Лекция 9 Делегаты.
Особенности C# Индексаторы, события, частичные методы, расширяющие методы, сборщик мусора DraggonZ.
СОБЫТИЯ Лекция 1. Взаимодействие объектов 2 Взаимодействие между объектами A и B можно организовать двумя способами. 1.Объект A вызывает метод объекта.
Делегаты Делегат эти объект, который безопасно инкапсулирует метод, его действие схоже с указателем функции в C и C++. Делегаты используются для передачи.
CобытияCобытияСобытия События представляют собой механизм, посредством которого объект имеет возможность получать информацию о происходящем вне него. Объявление.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
Полиморфизм. Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Виды проектов Visual Studio.Net 2012 предлагает различные шаблоны для ваших начальных проектов. Основные поддерживаемые языки программирования: С#, C++,
События События Важная роль делегатов заключается в том, что на них основана модель событий С#. Применение событий вовсе не ограничено приложениями с графическим.
В С# предусмотрены средства для создания пользовательских классов-контейнеров, к внутренним элементам которых можно обращаться при помощи того же оператора.
С# и ООП Формальное определение класса с C# Класс в C# - это пользовательский тип данных (user defined type), который состоит из данных (часто называемых.
Делегаты Как созданные объекты могут посылать сообщения тем объектам, которые их породили? При программировании под Windows на С и C++ основное средство.
Ресурсы WPF Два типа ресурсов WPF: объектные ресурсы (object resource) – определенный.NET-объект, который можно использовать многократно; ресурсы сборки.
Основы ООП и C# Работа с объектами и классами. Классы Класс специальный тип данных для описания объектов. Он определяет данные и поведение типа. Определение.
Учебный курс Объектно-ориентированный анализ и программирование Лекция 7 Методы как средство реализации операций Лекции читает кандидат технических наук.
1 © Luxoft Training 2012 Java: расширенные вопросы Модуль #8.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
Транксрипт:

События (events) События позволяют классу или объекту уведомлять другие классы или объекты о возникновении каких-либо ситуаций. Событие представляет собой сообщение, посылаемое объектом, чтобы сигнализировать о совершении какого-либо действия. Это действие может быть вызвано в результате взаимодействия с пользователем, например при нажатии кнопки мыши, или может быть обусловлено логикой работы программы. Объект, вызывающий событие, называется отправителем события. Объект, который захватывает событие и реагирует на него, называется получателем события. Часто используются другие термины - издатель и подписчик. Конструкторы Деструкторы Константы Поля Методы Свойства Индексаторы Операторы События Делегаты Классы Интерфейсы Структуры

События имеют следующие свойства: Издатель определяет момент вызова события, подписчики определяют предпринятое ответное действие. У события может быть несколько подписчиков. Подписчик может обрабатывать несколько событий от нескольких издателей. События, не имеющие подписчиков, никогда не возникают. В библиотеке классов.NET Framework в основе событий лежит делегат EventHandler и базовый класс EventArgs. При обмене событиями классу отправителя событий не известен объект или метод, который будет получать (обрабатывать) сформированные отправителем события. Необходимо, чтобы между источником и получателем события имелся посредник (или механизм подобный указателю). С# определяет специальный тип (Delegate), обеспечивающий функциональные возможности указателя функции.

В следующем примере показан порядок объявления делегата событий. public delegate void AlarmEventHandler(object sender, AlarmEventArgs e); Синтаксис сходен с синтаксисом объявления метода. Однако зарезервированное слово delegate сообщает компилятору, что AlarmEventHandler является типом делегата. По соглашению делегаты событий в.NET Framework имеют два параметра: источник, вызвавший событие, и данные для события. Экземпляр делегата AlarmEventHandler можно привязать к любому методу, который соответствует его подписи, такому как метод AlarmRang класса WakeMeUp, как показано в следующем примере. public class WakeMeUp { // AlarmRang has the same signature as AlarmEventHandler. public void AlarmRang(object sender, AlarmEventArgs e) {...};... }

Функциональные возможности события обеспечивают три взаимосвязанные элемента: класс, предоставляющий данные события, делегат события и класс, вызывающий событие. EventName В среде.NET Framework используется соглашение по присвоению имен классам и методам, относящимся к событиям. Чтобы класс мог вызывать событие с именем EventName, необходимы следующие элементы: Класс, содержащий данные события, именуемый как EventNameEventArgs. Этот класс должен наследоваться от System.EventArgs. Делегат для события, именуемый как EventNameEventHandler. Класс, вызывающий событие. Этот класс должен предоставить объявление события (EventName) и метод, инициирующий событие (OnEventName).

Класс данных события и класс делегата события могут быть уже определены в библиотеке классов.NET Framework или в библиотеке классов независимых разработчиков. В данном случае не требуется определять эти классы. Например, если событие не использует пользовательские данные, то можно использовать System.EventArgs для данных события и System.EventHandler для делегата.

Элемент события определяется в классе с помощью ключевого слова event. Когда компилятор обнаруживает ключевое слово event в классе, он создает закрытый элемент, например: private EventNameHandler eh = null; Компилятор также создает два открытых метода add_EventName и remove_EventName. Эти методы являются обработчиками событий, которые позволяют объединять или удалять делегаты из делегата события eh. Эти подробности скрыты от программиста.

public class SampleEventArgs { public SampleEventArgs(string s) { Text = s; } public String Text {get; private set;} // readonly } public class Publisher { public delegate void SampleEventHandler(object sender, SampleEventArgs e); public event SampleEventHandler SampleEvent; // Declare the event. // Wrap the event in a protected virtual method // to enable derived classes to raise the event. protected virtual void RaiseSampleEvent() { if (SampleEvent != null) SampleEvent(this, new SampleEventArgs("Hello")); }

События это особый тип многоадресных делегатов, которые можно вызвать только из класса или структуры, в которой они объявлены (класс издателя). Если на событие подписаны другие классы или структуры, их методы обработчиков событий будут вызваны когда класс издателя инициирует событие. События можно пометить как открытые (public), закрытые (private), защищенные (protected), внутренние (internal) или protectedinternal. Эти модификаторы доступа определяют порядок доступа к классу для пользователей класса. ключевое словоОписание staticДелает событие доступным для вызова в любое время, даже если экземпляр класса отсутствует. virtualПозволяет производным классам переопределять поведение события при помощи ключевого слова override.override sealedУказывает, что для производных классов событие более не является виртуальным. abstractКомпилятор не создаст блоки методов доступа к событиям add и remove и, следовательно, производные классы должны предоставлять собственную реализацию.

Подписка и отмена подписки на события Необходимость подписки на событие, опубликованное другим классом, может возникнуть когда требуется написать пользовательский код, вызываемый при инициировании такого события. Например, можно подписаться на событие кнопки click, чтобы приложение выполняло некоторое действие при нажатии пользователем на кнопку.

Подписка на события в среде IDE Visual Studio 1.Если окно Свойства закрыто, в представлении Конструктор щелкните правой кнопкой мыши форму или элемент управления, для которого требуется создать обработчик событий, и выберите пункт Свойства. 2.Вверху окна Свойства щелкните значок События. 3.Дважды щелкните событие, которое требуется создать, например событие Load. Visual C# создаст пустой метод обработчика событий и добавит его в код. Код можно также добавить вручную в представлении Код.

private void Form1_Load(object sender, System.EventArgs e) { // Add your form load event handling code here. } Строка кода, требуемая для подписки на событие, также создается автоматически в методе InitializeComponent в файле Form1.Designer.cs проекта. Она имеет следующий вид. this.Load += new System.EventHandler(this.Form1_Load); Например, следующие строки кода объявляют метод обработчика событий, который будет выполнен при инициировании классом Form события Load.

Подписка на события программными средствами 1.Определите метод обработчика событий, подпись которого соответствует подписи делегата для события. Например, если событие основано на типе делегата EventHandler, то следующий код представляет заглушку метода: void HandleCustomEvent(object sender, CustomEventArgs a) { // Do something useful here. } 2. Чтобы присоединить обработчик событий к событию, используйте оператор назначения сложения (+=). В следующем примере предположим, что объект с именем publisher имеет событие с именем RaiseCustomEvent. Обратите внимание, что для класса подписчика требуется ссылка на класс издателя, чтобы подписаться на его события. publisher.RaiseCustomEvent += HandleCustomEvent;

Приведенный выше синтаксис появился только в C# 2.0. Он в точности соответствует синтаксису C# 1.0, в котором при помощи ключевого слова new должен быть явно создан инкапсулирующий делегат: publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent); Для добавления обработчика событий можно также использовать лямбда- выражение. public Form1() { InitializeComponent(); this.Click += (s,e) => { MessageBox.Show( ((MouseEventArgs)e).Location.ToString()); }; }

Подписка на события при помощи анонимного метода Если не нужно будет позже отменять подписку на событие, можно использовать оператор назначения сложения (+=) для прикрепления к событию анонимного метода. В следующем примере предположим, что объект с именем publisher имеет событие с именем RaiseCustomEvent, и что класс CustomEventArgs также был определен и содержит некие относящиеся к событию сведения. Обратите внимание, что для класса подписчика требуется ссылка на publisher, чтобы подписаться на его события. publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e) { string s = o.ToString() + " " + e.ToString(); Console.WriteLine(s); }; Отменить подписку на событие не так просто, если для подписки на него использовалась анонимная функция. Чтобы отменить подписку в этом случае, необходимо вернуться к коду, в котором была выполнена подписка на событие, сохранить анонимный метод в переменной делегата, а затем добавить делегат к событию. Как правило, не рекомендуется использовать анонимные функции для подписки на события, если предполагается, что в будущем будет нужно отменять подписку на событие.

Отмена подписки Чтобы предотвратить вызов обработчика событий при инициировании события, подписку на событие необходимо отменить. Во избежание утечки ресурсов отменять подписку на события следует до удаления объекта подписчика. До тех пор, пока подписка на событие не отменена, делегат многоадресной рассылки, лежащий в основе события в публикующем объекте, будет ссылаться на делегат, инкапсулирующий обработчик событий подписчика. Если ссылка присутствует в публикующем объекте, объект подписчика не будет удален при сборке мусора publisher.RaiseCustomEvent -= HandleCustomEvent ; Если подписка на событие отменена для всех подписчиков, экземпляр события в классе издателя получает значение null.

После определения реализации события, необходимо определить, когда следует инициировать событие. Событие инициируется вызовом защищенного метода OnEventName в классе, определяющем событие, или в производном классе. Метод OnEventName вызывает событие посредством вызова делегатов, передавая все характерные для события данные. Методы делегата события могут выполнять действия для события или обрабатывать характерные для события данные.

Пользовательские делегаты событий необходимы только в случаях, когда событие создает данные для события. Многие события, включая некоторые события пользовательского интерфейса, например щелчки мышью, не создают данных для события. В таких ситуациях делегат события, предоставляемый библиотекой классов для события без данных, System.EventHandler является целесообразным. Его объявление приводится ниже. delegate void EventHandler(object sender, EventArgs e);.NET Framework 2.0 представляет общую версию данного делегата EventHandler. В следующей процедуре показано добавление событий, соответствующих стандартному шаблону.NET Framework для пользовательских классов и структур.

Порядок публикации событий, основанных на шаблоне EventHandler 1.(Пропустите этот шаг и перейдите к шагу 3a, если не требуется передавать с событием пользовательские данные.) Объявите класс для пользовательских данных в области, видимой для классов издателя и подписчика. Затем добавьте необходимые члены для хранения данных пользовательских событий. В данном примере возвращается простая строка. public class CustomEventArgs : EventArgs { public CustomEventArgs(string s) { msg = s; } private string msg; public string Message { get { return msg; } } }

2. (Пропустите данный шаг, если используется общая версия EventHandler.) Объявите делегат в своем классе публикации. Назначьте ему имя, заканчивающееся на EventHandler. Второй параметр задает ваш тип EventArgs. public delegate void CustomEventHandler(object sender, CustomEventArgs a);

3.Объявите событие в своем классе публикации с помощью одного из следующих действий. Если пользовательский класс EventArgs отсутствует, ваш тип Event представляет собой не являющийся общим делегат EventHandler. Этот делегат не нужно объявлять, так как он уже объявлен в пространстве имен System, добавленном при создании проекта C#. Добавьте следующий код в класс издателя. public event EventHandler RaiseCustomEvent ; При использовании неуниверсальной версии типа EventHandler и наличии пользовательского класса, производного от типа EventArgs, объявите событие внутри класса публикации и используйте делегат из пункта 2 в качестве типа. public event CustomEventHandler RaiseCustomEvent ; Если используется универсальная версия, то пользовательский делегат не требуется. Вместо этого в классе публикации необходимо задать тип события как EventHandler, заключив имя пользовательского класса в угловые скобки. public event EventHandler RaiseCustomEvent ;

namespace DotNetEvents { using System; using System.Collections.Generic; // Класс для хранения пользовательской информации public class CustomEventArgs : EventArgs { public CustomEventArgs(string s) { message = s; } private string message; public string Message { get { return message; } set { message = value; } } }

// Класс для публикации событий class Publisher { public event EventHandler RaiseCustomEvent; // Декларирует событие public void DoSomething() { // Здесь код, который что-то делает полезное, затем вызывает событие. // Можно создать событие, прежде чем выполнять блок кода OnRaiseCustomEvent(new CustomEventArgs("Did something")); } protected virtual void OnRaiseCustomEvent(CustomEventArgs e) { // Make a temporary copy of the event to avoid possibility of // a race condition if the last subscriber unsubscribes // immediately after the null check and before the event is raised. EventHandler handler = RaiseCustomEvent; if (handler != null) // Событие null если нет подписчиков { e.Message += String.Format(" at {0}", DateTime.Now.ToString()); handler(this, e); }

//Класс, который подписывается на события class Subscriber { private string id; public Subscriber(string ID, Publisher pub) { id = ID; // Подписаться на событие (C# 2.0 syntax) pub.RaiseCustomEvent += HandleCustomEvent; } // Определить какие действия необходимо предпринять при // возникновении события void HandleCustomEvent(object sender, CustomEventArgs e) { Console.WriteLine(id + " received this message: {0}", e.Message); }

class Program { static void Main(string[] args) { Publisher pub = new Publisher(); Subscriber sub1 = new Subscriber("sub1", pub); Subscriber sub2 = new Subscriber("sub2", pub); pub.DoSomething(); // Вызов метода, который вызывает событие Console.WriteLine("Press Enter to close this window."); Console.ReadLine(); }