События и делегаты
Событие представляет собой сообщение, посылаемое объектом, чтобы сигнализировать о совершении какого-либо действия. Это действие может быть вызвано в результате взаимодействия с пользователем, например при нажатии кнопки мыши, или может быть обусловлено логикой работы программы. Объект, вызывающий событие, называется отправителем события. Объект, который захватывает событие и реагирует на него, называется получателем события.
При обмене событиями классу отправителя событий не известен объект или метод, который будет получать (обрабатывать) сформированные отправителем события. Необходимо, чтобы между источником и получателем события имелся посредник (или механизм подобный указателю). .NET Framework определяет специальный тип (Delegate), обеспечивающий функциональные возможности указателя функции.
Делегат является классом, который может хранить ссылку на метод. В отличие от других классов класс делегата имеет сигнатуру и может хранить ссылки только на методы, соответствующие этой сигнатуре. Таким образом, делегат эквивалентен типобезопасному указателю функции или обратному вызову. Хотя делегаты имеют и другие направления использования, здесь будут рассматриваться только функциональные возможности делегатов по обработке событий. Объявление делегата является достаточным для определения класса делегата. Объявление предоставляет сигнатуру делегата, а среда CLR обеспечивает реализацию. В следующем примере показан порядок объявления делегата событий.
Public Delegate Sub AlarmEventHandler(sender As Object, e As AlarmEventArgs)
public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);
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 Sub AlarmRang(sender As Object, e As AlarmEventArgs)
'...
End Sub
'...
End Class
public class WakeMeUp
{
// AlarmRang has the same signature as AlarmEventHandler.
public void AlarmRang(object sender, AlarmEventArgs e)
{
//...
}
//...
}
public ref class WakeMeUp
{
public:
// AlarmRang has the same signature as AlarmEventHandler.
void AlarmRang(Object^ sender, AlarmEventArgs^ e)
{
//...
}
//...
};
Пользовательские делегаты событий необходимы только в случаях, когда событие создает данные для события. Многие события, включая некоторые события пользовательского интерфейса, например щелчки мышью, не создают данных для события. В таких ситуациях делегат события, предоставляемый библиотекой классов для события без данных, System.EventHandler является целесообразным. Его объявление приводится ниже.
Delegate Sub EventHandler(sender As Object, e As EventArgs)
delegate void EventHandler(object sender, EventArgs e);
delegate void EventtHandler(Object^ sender, EventArgs^ e);
Делегаты событий являются многоадресными. Это означает, что они могут хранить ссылки на несколько методов обработки событий. Дополнительные сведения см. в разделе Delegate. Делегаты позволяют осуществлять гибкий и детальный контроль при обработке событий. Делегат действует как диспетчер событий для класса, вызвавшего событие, обслуживая для события список зарегистрированных обработчиков событий.
Сведения об использовании делегатов для предоставления функциональных возможностей событий в компоненте или элементе управления содержатся в разделе Создание событий.
Общие сведения о потреблении событий в приложениях содержатся в разделе Потребление событий.
См. также
Задачи
Практическое руководство. Вызов и прием событий
Практическое руководство. Соединение методов обработчика событий с событиями