Что такое событие в программировании
Перейти к содержимому

Что такое событие в программировании

  • автор:

Учебники. Программирование для начинающих.

Programm.ws — это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..

Программирование — в обычном понимании, это процесс создания компьютерных программ.
В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками.
В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.

Delphi для профессионалов

Глава 1 Объектно-ориентированное программирование

События

Программистам, давно работающим в Windows, наверное, не нужно пояснять смысл термина «событие». Сама эта среда и написанные для нее программы управляются событиями, возникающими в результате воздействий пользователя, аппаратуры компьютера или других программ. Весточка о наступлении события — это сообщение Windows, полученное так называемой функцией окна. Таких сообщений сотни, и, по большому счету, написать программу для Windows — значит определить и описать реакцию на некоторые из них.

Работать с таким количеством сообщений, даже имея под рукой справочник, нелегко. Поэтому одним из больших преимуществ Delphi является то, что программист избавлен от необходимости работать с сообщениями Windows (хотя такая возможность у него есть). Типовых событий в Delphi — не более двух десятков, и все они имеют простую интерпретацию, не требующую глубоких знаний среды.

Рассмотрим, как реализованы события на уровне языка Object Pascal. Событие — это свойство процедурного типа, предназначенное для создания пользовательской реакции на то или иное входное воздействие:

property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;

Здесь FOnMyEvent — поле процедурного типа, содержащее адрес некоторого метода. Присвоить такому свойству значение — значит указать объекту адрес метода, который будет вызываться в момент наступления события. Такие методы называют обработчиками событий. Например, запись:

означает, что при активизации объекта Application (так называется объект, соответствующий работающему приложению) будет вызван метод-обработчик MyActivatingMethod .

Внутри библиотеки времени выполнения Delphi вызовы обработчиков событий находятся в методах, обрабатывающих сообщения Windows. Выполнив необходимые действия, этот метод проверяет, известен ли адрес обработчика, и, если это так, вызывает его:

if Assigned(FOnMyEvent) then FOnMyEvent(Self);

События имеют разное количество и тип параметров в зависимости от происхождения и предназначения. Общим для всех является параметр sender — он указывает на объект-источник события. Самый простой тип — TNotifyEvent — не имеет других параметров:

TNotifyEvent = procedure (Sender: TObject) of object;

Тип метода, предназначенный для извещения о нажатии клавиши, предусматривает передачу программисту кода этой клавиши о передвижении мыши — ее текущих координат и т. п. Все события в Delphi принято предварять префиксом On: onCreate, onMouseMove, onPaint и т. д. Дважды щелкнув в Инспекторе объектов на странице Events в поле любого события, вы получите в программе заготовку метода нужного типа. При этом его имя будет состоять из имени текущего компонента и имени события (без префикса On), а относиться он будет к текущей форме. Пусть, например, на форме Forml есть текст Label1 . Тогда для обработки щелчка мышью (событие O nclick ) будет создана заготовка метода TFormi.Label1click:

procedure TForml.LabellClick(Sender: TObject);

begin

end;

Поскольку события — это свойства объекта, их значения можно изменять в любой момент во время выполнения программы. Эта замечательная возможность называется делегированием. Можно в любой момент взять способы реакции на события у одного объекта и присвоить (делегировать) их другому:

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

Но какой механизм позволяет подменять обработчики, ведь это не просто процедуры, а методы? Здесь как нельзя кстати приходится существующее в Object Pascal понятие указателя на метод. Отличие метода от процедуры состоит в том, что помимо явно описанных параметров методу всегда неявно передается еще и указатель на вызвавший его экземпляр класса (переменная self ). Вы можете описать процедурный тип, который будет совместим по присваиванию с методом (т. е. предусматривать получение self ). Для этого в описание процедуры нужно добавить зарезервированные слова of object . Указатель на метод — это указатель на такую процедуру.

type

TMyEvent = procedure(Sender: TObject; var AValue: Integer) of object;

TlstObject = class;

FOnMyEvent: TMyEvent;

property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;

end;

T2ndObject = class;

procedure SetValuel(Sender: TObject; var AValue: Integer);

procedure SetValue2(Sender: TObject; var AValue: Integer);

end;

.

var

Objl: TlstObject;

Obj2: T2ndObject;

begin

Objl := TlstObject.Create;

Obj2 := T2ndObject.Create;

Obj1.OnMyEvent := Obj2.SetValuel;

Obj1.OnMyEvent := Obj2.SetValue2;

.

end.

Этот пример показывает, что при делегировании можно присваивать методы других классов. Здесь обработчиком события OnMyEvent объекта Objl по очереди выступают методы SetValuel и Setvaiue2 объекта Obj2 .

Обработчики событий нельзя сделать просто процедурами — они обязательно должны быть чьими-то методами. Но их можно «отдать» какому-либо другому объекту. Более того, для этих целей можно описать и создать специальный объект. Его единственное предназначение — быть носителем методов, которые затем делегируются другим объектам. Разумеется, такой объект надо не забыть создать до использования его методов, а в конце — уничтожить. Можно и не делать этого, объявив методы методами класса, о которых речь пойдет в одном из последующих разделов.

Мы сейчас решили задачу использования нескольких разных обработчиков того или иного события для одного объекта. Но не менее часто требуется решить обратную задачу — а как использовать для различных событий разных объектов один и тот же обработчик?

Если никакой «персонификации» объекта, вызвавшего метод, не нужно, все делается тривиально и проблемы не возникает. Самый простой пример: в современных программах основные функции дублируются дважды — в меню и на панели инструментов. Естественно, сначала нужно создать и наполнить метод содержимым (скажем, для пункта меню), а затем в Инспекторе объектов указать его же для кнопки панели инструментов.

Более сложный случай, когда внутри такого метода нужно разобраться, кто собственно его вызвал. Если потенциальные кандидаты имеют разный объектный тип (как в предыдущем абзаце — кнопка и пункт меню), то именно объектный тип можно применить в качестве критерия:

If Sender is TMenuItem then ShowMessage(‘Выбран пункт меню’);

Если же все объекты, разделяющие между собой один обработчик события, относятся к одному классу, то приходится прибегать к дополнительным ухищрениям. Типовой прием — использовать свойство Tag , которое имеется у всех компонентов, и, вполне вероятно, именно для этого и задумывалось:

const colors : array[0..7]

of

TColor = clWhite,clRed,clBlue,clYellow,clAqua,clGreen, clMaroon,clBlack);

procedure TForml.CheckBoxClick(Sender: TObject);

begin

with TCheckBox(Sender) do

if Checked

then Color := Colors[Tag]

else Color := clBtnFace;

end;

Пусть в форме имеется несколько переключателей. Для того чтобы при нажатии каждый из них окрашивался в свой цвет, нужно в Инспекторе объектов присвоить свойству Tag значения от 0 до 7 и для каждого связать событие onclick с методом CheckBoxClick . Этот единственный метод справится с задачей для всех переключателей.

События

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

Важной дополнительной возможностью, обеспечиваемой объектами событий, является то, что переход в сигнальное состояние единственного объекта события способен вывести из состояния ожидания одновременно несколько потоков. Объекты события делятся на сбрасываемые вручную и автоматически сбрасываемые, и это их свойство устанавливается при вызове функции CreateEvent.

• Сбрасываемые вручную события (manual-reset events) могут сигнализировать одновременно всем потокам, ожидающим наступления этого события, и переводятся в несигнальное состояние программно.

• Автоматически сбрасываемые события (auto-reset event) сбрасываются самостоятельно после освобождения одного из ожидающих потоков, тогда как другие ожидающие потоки продолжают ожидать перехода события в сигнальное состояние.

События используют пять новых функций: CreateEvent, OpenEvent, SetEvent, ResetEvent и CreateEvent.

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpsa, BOOL bManualReset, BOOL bInitialState, LPTCSTR lpEventName)

Чтобы создать событие, сбрасываемое вручную, необходимо установить значение параметра bManualReset равным True. Точно так же, чтобы сделать начальное состояние события сигнальным, установите равным True значение параметра bInitialState. Для открытия именованного объекта события используется функция OpenEvent, причем это может сделать и другой процесс.

Для управления объектами событий используются следующие три функции:

BOOL SetEvent(HANDLE hEvent)

BOOL ResetEvent(HANDLE hEvent)

BOOL PulseEvent(HANDLE hEvent)

Поток может установить событие в сигнальное состояние, используя функцию SetEvent. Если событие является автоматически сбрасываемым, то оно автоматически возвращается в несигнальное состояние уже после освобождения только одного из ожидающих потоков. В отсутствие потоков, ожидающих наступления этого события, оно остается в сигнальном состоянии до тех пор, пока такой поток не появится, после чего этот поток сразу же освобождается. Заметьте, что таким же образом ведет себя семафор, максимальное значение счетчика которого установлено равным 1.

С другой стороны, если событие является сбрасываемым вручную, то оно остается в сигнальном состоянии до тех пор, пока какой-либо поток не вызовет функцию ResetEvent, указав дескриптор этого события в качестве аргумента. В это время все ожидающие потоки освобождаются, но до выполнения такого сброса события другие потоки могут как переходить в состояние его ожидания, так и освобождаться.

Функция PulseEvent освобождает все потоки, ожидающие наступления сбрасываемого вручную события, но после этого событие сразу же автоматически сбрасывается. В случае же использования автоматически сбрасываемого события функция PulseEvent освобождает только один ожидающий поток, если таковые имеются.

Примечание

Хотя в книгах многих авторов и даже в некоторых документах Microsoft (см. примечания в разделе MSDN, содержащем описание функции PulseEvent) рекомендуется избегать использования функции PulseEvent, лично я считаю эту функцию не только полезной, но и существенно важной, как это следует из обсуждения многочисленных примеров, приведенных в двух следующих главах.

Следует отметить, что функция PulseEvent становится полезной лишь после того, как сбрасываемое вручную событие установлено в сигнальное состояние с помощью функции SetEvent. Будьте внимательны, когда используете функцию WaitForMultipleObjects для ожидания перехода в сигнальное состояние всех событий. Ожидающий поток освободится только тогда, когда одновременно все события будут находиться в сигнальном состоянии, и некоторые из событий, находящихся в сигнальном состоянии, могут быть сброшены, прежде чем поток освободится.

В упражнении 8.5 вам предлагается изменить программу sortMT (программа 7.2) за счет использования в ней событий.

Переменные условий (condition variables) Pthreads в некоторой степени сравнимы с событиями, но используются в сочетании с мьютексами. Такой способ их использования в действительности является очень плодотворным и будет описан в главе 10. Для создания и уничтожения переменной условий используются, соответственно, системные вызовы pthread_cond_init и pthread_cond_destroy. Функциями ожидания являются pthread_cond_wait и pthread_cond_timedwait. Системный вызов pthread_cond_signal осуществляет возврат после освобождения одного ожидающего потока аналогично Windows-функции PulseEvent в случае автоматически сбрасываемых событий, тогда как вызов pthread_cond_broadcast сигнализирует всем ожидающим потокам, и поэтому его можно сопоставить функции PulseEvent, применяемой к сбрасываемому вручную событию. Эквивалентов функций PulseEvent и ResetEvent, используемых в случае сбрасываемых вручную событий, не существует.

Читайте также

События

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

Исключения и события MI

Исключения и события MI В MI различаются исключения и события. Исключение — это либо ошибка, обнаруженная машиной при исполнении команды, либо определенное состояние, обнаруженное пользовательской программой. Событие — это происшествие, возникающее в процессе работы

Главные события

Главные события Когда выполняется процедура типа Sub, не отображающая форм, ваш программный код полностью контролирует, что и когда делает программа. Но если на экране отображается форма, программа переходит в каком-то смысле в пассивное состояние, ожидая инструкций от

События

События Событие представляет собой нечто, случающееся с объектом, и на что объект может ответить заранее предусмотренным действием. К событиям можно отнести следующее.* Физические действия пользователя программы, например щелчок кнопкой мыши, перемещение курсора,

Звуковые события

Звуковые события Звуковое сопровождение помогает лучше ориентироваться в происходящих событиях, и Windows XP имеет большое количество заготовок, необходимо только связать событие с конкретным звуковым файлом. Например, при получении писем – один звуковой сигнал, при

13.2.7. Ожидание события

13.2.7. Ожидание события Часто один или несколько потоков следят за «внешним миром», а остальные выполняют полезную работу. Все примеры в этом разделе надуманные, но общий принцип они все же иллюстрируют.В следующем примере прикладную задачу решают три потока. Четвертый

События в C#

События в C# Делегаты оказываются очень интересными конструкциями с той точки зрения, что они предоставляют возможность реализовать двухстороннее взаимодействие между объектами в памяти. Однако, и вы с этим согласитесь, работа с делегата-ми напрямую предполагает ввод

«Разборчивые» события

«Разборчивые» события Есть еще одно усовершенствование, которое можно внести в наш пример с CarEvents и которое соответствует шаблону событий, рекомендуемому разработчиками из Microsoft. При исследовании событий, посылаемых данным типом из библиотек базовых классов, вы

8.3. Метаданные события

8.3. Метаданные события Информация относительно событий может быть получена следующим образом:Запрос таблицы EVENTS базы данных INFORMATION_SCHEMAИспользование инструкции SHOW EVENTS.Использование инструкции SHOW CREATE EVENT.Запись событий, выполненных на сервере, может читаться из файла

События

События События Firebird являются «сигналами», которые модули PSQL могут накапливать в процессе выполнения для передачи клиентским приложениям, когда работа будет подтверждена. Клиентские приложения в сети могут прослушивать- с использованием обработчика сообщений-

Переменные события

Переменные события В Firebird появляются логические контекстные переменные INSERTING, UPDATING и DELETING, чтобы поддерживать условные переходы для триггеров, используемых для нескольких событий. Возможным синтаксисом ветвления может быть:IF (OR [OR

События

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

1.1.7 События

1.1.7 События Когда пользователь нажимает на кнопку мыши или клавишу клавиатуры, или когда окно программы нуждается в перерисовке, или когда происходят другие изменения в системе, сервер подготавливает соответствующий пакет данных и отправляет его той или иной программе

Простейшие события

Простейшие события Рисование мышью в графическом окне Данная программа осуществляет рисование мышью в графическом окне:uses GraphABC;procedure MouseDown(x,y,mb: integer);beginMoveTo(x,y);end;procedure MouseMove(x,y,mb: integer);beginif mb=1 then LineTo(x,y);end;begin // Привязка обработчиков к событиямOnMouseDown := MouseDown;OnMouseMove :=

СОБЫТИЯ: Мы VAS не хотим!

СОБЫТИЯ: Мы VAS не хотим! 17-18 ноября в Санкт-Петербурге состоялась вторая специализированная международная конференция Mobile VAS Conference, на которую съехалось больше трехсот специалистов и представителей компаний из стран СНГ, Европы и Азии, действующих на рынке дополнительных

Обработка и инициация событий

События в .NET основаны на модели делегата. Модель делегата соответствует шаблону разработки наблюдателя, который позволяет подписчику зарегистрироваться у поставщика и получать от него уведомления. Отправитель события отправляет уведомление о событии, а приемник событий получает уведомление и определяет ответ на него. В этом разделе описываются основные компоненты модели делегата, использование событий в приложениях и реализация событий в коде.

События

Событие — это сообщение, посланное объектом, чтобы сообщить о совершении действия. Это действие может быть вызвано пользовательским взаимодействием, например нажатием кнопки, или какой-то другой программной логикой, например изменением значения свойства. Объект, вызывающий событие, называется отправителем событий. Отправителю событий не известен объект или метод, который будет получать (обрабатывать) созданные им события. Обычно событие является членом отправителя событий; например, событие Click — член класса Button, а событие PropertyChanged — член класса, реализующего интерфейс INotifyPropertyChanged.

Чтобы определить событие, необходимо использовать ключевое слово event в C# или Event в Visual Basic в сигнатуре класса события и задать тип делегата для события. Делегаты описаны в следующем разделе.

Как правило, для вызова события добавляется метод, помеченный как protected и virtual (в C#) или Protected и Overridable (в Visual Basic). Назовите этот метод On EventName; например, OnDataReceived . Метод должен принимать один параметр, который определяет объект данных события, являющийся объектом типа EventArgs или производного типа. Этот метод предоставляется, чтобы производные классы могли переопределять логику для вызова события. Производный класс должен вызывать метод On EventName базового класса, чтобы зарегистрированные делегаты получили событие.

В следующем примере показан способ объявления события ThresholdReached . Событие связано с делегатом EventHandler и возникает в методе OnThresholdReached .

class Counter < public event EventHandler ThresholdReached; protected virtual void OnThresholdReached(EventArgs e) < EventHandler handler = ThresholdReached; handler?.Invoke(this, e); >// provide remaining implementation for the class > 
Public Class Counter Public Event ThresholdReached As EventHandler Protected Overridable Sub OnThresholdReached(e As EventArgs) RaiseEvent ThresholdReached(Me, e) End Sub ' provide remaining implementation for the class End Class 

Делегаты

Делегат — это тип, содержащий ссылку на метод. Делегат объявляется с сигнатурой, указывающей тип возвращаемого значения и параметры для методов, на которые он ссылается, и может содержать ссылки только на методы, соответствующие его сигнатуре. Таким образом, делегат эквивалентен указателю на строго типизированную функцию или обратному вызову. Объявления делегата достаточно для определения класса делегата.

У делегатов широкая область применения в .NET. В контексте событий делегат — это посредник (или механизм, подобный указателю) между источником события и кодом, обрабатывающим событие. Делегат связывается с событием за счет включения типа делегата в объявление события, как показано в примере в предыдущем разделе. Дополнительные сведения о делегатах см. в разделе, посвященном классу Delegate.

Эти делегаты являются многоадресными, то есть в них могут храниться ссылки на несколько методов обработки событий. Дополнительные сведения см. на справочной странице класса Delegate. Делегаты позволяют гибко и точно управлять обработкой событий. Делегат выступает как диспетчер событий для класса, вызывающий событие за счет ведения списка зарегистрированных обработчиков для события.

public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e); 
Public Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs) 

Данные событий

Данные, связанные с событием, могут быть предоставлены с помощью класса данных события. .NET предоставляет множество классов данных событий, которые можно использовать в приложениях. Например, класс SerialDataReceivedEventArgs — класс данных события SerialPort.DataReceived. В .NET имена всех классов данных событий оканчиваются ключевым словом EventArgs . Определить, какой класс данных события связан с событием, можно по делегату этого события. Например, делегат SerialDataReceivedEventHandler содержит класс SerialDataReceivedEventArgs в качестве одного из своих параметров.

Класс EventArgs является базовым типом для всех классов данных событий. Класс EventArgs используется также, если событие не содержит связанных данных. При создании события, которое лишь уведомляет другие классы о том, что что-то произошло, и не передает никаких данных, используйте класс EventArgs в качестве второго параметра в делегате. Если данные не предоставляются, можно передать значение EventArgs.Empty. Делегат EventHandler содержит класс EventArgs в качестве параметра.

Если требуется создать пользовательский класс данных события, создайте класс, производный от класса EventArgs, а затем укажите все члены, необходимые для передачи данных, связанных с событием. В большинстве случаев следует использовать схему именования .NET и завершать имя класса данных события ключевым словом EventArgs .

В следующем примере показан класс данных события с именем ThresholdReachedEventArgs . Он содержит свойства, относящиеся только к вызываемому событию.

public class ThresholdReachedEventArgs : EventArgs < public int Threshold < get; set; >public DateTime TimeReached < get; set; >> 
Public Class ThresholdReachedEventArgs Inherits EventArgs Public Property Threshold As Integer Public Property TimeReached As DateTime End Class 

Обработчики событий

Для обработки события в приемнике события необходимо определить метод обработчика события. Этот метод должен соответствовать сигнатуре делегата обрабатываемого события. В обработчике событий выполняются действия, необходимые при возникновении события, например сбор данных, введенных пользователем при нажатии кнопки. Чтобы получать уведомления при возникновении события, метод обработчика события должен быть подписан на событие.

В следующем примере показан метод обработчика события c_ThresholdReached , который соответствует сигнатуре делегата EventHandler. Метод подписывается на событие ThresholdReached .

class Program < static void Main() < var c = new Counter(); c.ThresholdReached += c_ThresholdReached; // provide remaining implementation for the class >static void c_ThresholdReached(object sender, EventArgs e) < Console.WriteLine("The threshold was reached."); >> 
Module Module1 Sub Main() Dim c As New Counter() AddHandler c.ThresholdReached, AddressOf c_ThresholdReached ' provide remaining implementation for the class End Sub Sub c_ThresholdReached(sender As Object, e As EventArgs) Console.WriteLine("The threshold was reached.") End Sub End Module 

Обработчики статических и динамических событий

.NET позволяет подписчикам регистрироваться для получения уведомлений о событиях как статически, так и динамически. Обработчики статических событий действуют в течение всего жизненного цикла класса, события которого они обрабатывают. Обработчики динамических событий активируются и деактивируются во время выполнения программы, обычно в ответ на определенную условную логику программы. Например, они могут использоваться, если уведомления о событиях требуются только в определенных условиях, либо приложение предоставляет несколько обработчиков событий и выбор конкретного обработчика зависит от условий среды выполнения. В примере в предыдущем разделе показано, как динамически добавлять обработчик события. Дополнительные сведения см. в разделах события (в Visual Basic) и события (в C#).

Создание нескольких событий

Если класс создает несколько событий, компилятор создает одно поле для каждого экземпляра делегата события. При большом количестве событий стоимость хранения одного поля на делегата может оказаться неприемлемой. Для таких случаев .NET предоставляет свойства события, которые можно использовать вместе с другой структурой данных для хранения делегатов события.

Свойства событий состоят из объявлений событий и методов доступа к событиям. Методы доступа к событиям — это определяемые пользователем методы, добавляющие или удаляющие экземпляры делегата события из структуры данных хранения. Обратите внимание, что использование свойств события снижает быстродействие по сравнению с полями события, поскольку перед вызовом каждого делегата события его необходимо извлечь. Необходимо найти компромисс между памятью и скоростью. Если ваш класс определяет много событий, которые вызываются нечасто, необходимо реализовать свойства событий. Дополнительные сведения см. в разделе Практическое руководство. Обработка нескольких событий с помощью их свойств.

Связанные статьи

Заголовок Описание
Практическое руководство. Вызов и прием событий Содержит примеры вызова и приема событий.
Практическое руководство. Обработка нескольких событий с помощью их свойств Показывает, как использовать свойства событий для обработки нескольких событий.
Шаблон разработки наблюдателя Описывает шаблон разработки, позволяющий подписчику зарегистрироваться у поставщика и получать от него уведомления.

См. также

  • EventHandler
  • EventHandler
  • EventArgs
  • Delegate
  • События (Visual Basic)
  • События (Руководство по программированию в C#)
  • Общие сведения о событиях и перенаправленных событиях (приложения для UWP)
  • События в приложениях Магазина Windows 8.x

События

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

Класс, которому требуется сообщать о возникновении некоторых ситуаций – событий, должен уметь делать следующее:

  • • объявить тип делегата, соответствующего событию;
  • • объявить событие в классе (экземпляр делегата);
  • • инициировать в нужный момент событие, передав обработчику необходимые для его работы параметры (т. е. некоторым способом уведомить клиентов класса, что у него произошло событие).

Инициируя событие, класс посылает сообщение получателям события – объектам некоторых других классов. Класс, инициирующий событие, называется отправителем сообщения (sender). Классы, чьи объекты получают сообщения, называют классами-получателями сообщении (receiver). Класс-отправитель сообщения в принципе не знает своих получателей. Он просто инициирует событие. Одно и то же сообщение может быть получено и по-разному обработано произвольным числом объектов разных классов.

Интерфейсы и многие классы из библиотеки FCL обладают стандартным набором предопределенных событий.

Объявление события в классе

Сообщение, посылаемое при инициировании события, является аналогом вызова метода. Поскольку сигнатура посылаемого сообщения должна соответствовать сигнатуре принимаемого сообщения, то объявление события синтаксически должно задавать сигнатуру метода.

В C# работа событий реализуется с помощью делегатов. Каждое событие задается делегатом, описывающим сигнатуру метода, который будет обрабатывать сообщения (обработчика события). Объявление события – это двухэтапный процесс:

• Вначале объявляется делегат, как это рассматривалось ранее. Объявление делегата описывается в некотором классе. Но часто это объявление находится вне класса в пространстве имен. Например:

• Если делегат определен, то в классе, создающем события, достаточно объявить событие как экземпляр соответствующего делегата. При этом используется ключевое слово event (это гарантирует, что экземпляр события не может быть вызван в других классах). Объявление события выполняется следующим образом:

Ниже приведен пример объявления делегата и события, представляющего экземпляр этого делегата:

// Объявление делегата – новый тип данных public delegate void MyHandler(object о, int n);

// Объявление события класса – экземпляр делегата public event MyHandler MyEvent;

Для инициирования события требуется просто вызвать на выполнение экземпляр делегата. Например:

// проверка, что для события заданы обработчики if (MyEvent != null) MyEvent(this, i); // запускаем событие

Ниже приведен пример описания класса, в котором содержится метод, выполнение которого занимает достаточно долгое время. Данный метод сообщает о выполнении каждой десятой доли своей работы. Объекты, использующие данный метод, могут визуально информировать пользователей о ходе выполнения работы в данном методе:

// Объявление нового типа – делегата с параметрами:

// о – ссылка на объект, который инициировал событие

// п – процент выполненной работы

public delegate void MyHandler (object о, int n);

// объявление класса с событием

public class ClassWithEvent

// Создание экземпляра делегата – событие

public event MyHandler MyEvent;

// поле класса private int Volume = 0;

// конструктор класса – параметр – объем работы public EventClass(int p) 0) Volume = р;>

//описание метода выполняющего долгую работу

//(но в данном примере бессмысленную)

public void LongWork()

double s = 0; int k = 0;

int st = Volume /10; // десятая часть работы

int n = (int)(i*100.0)/Volume;

MyEvent(this, n); // запускаем событие

В данном примере в классе ClassWithEvent описан делегат MyHandler, сигнатура которого содержит три параметра. Событие MyEvent в классе ClassWithEvents является экземпляром класса, заданного делегатом.

Обработка событий в классах

Класс, который заинтересован в обработке событий, должен:

  • • иметь обработчик события – метод, согласованный по сигнатуре с сигнатурой делегата, который задает событие;
  • • иметь ссылку на объект, создающий событие, чтобы получить доступ к этому событию – event-объекту;
  • • присоединить обработчик события к event-объекту. Это реализуется с использованием операции += для описанного события.

Пример класса, использующего описанный ранее класс ClassWithEvent с событием, показан ниже:

const int WorkVolume = 10000000; // объем работы public static void Main()

ClassWithEvent obj=new ClassWithEvent(WorkVolume); // задается обработчик события

obj.MyEvent += new MyHandler(ShowStar);

// запускаем длинную работу у объекта а obj.LongWork();

// ждем нажатия клавиши Console. ReadLine();

private static void ShowStar(object о, int n)

Console.WriteLine(» Выполнено %», n);

//Console.Write(«*»); // можно просто выводить *

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *