Обработка и вызов событийHandling and Raising Events

События на платформе .NET Framework основаны на модели делегата.Events in the .NET Framework are based on the delegate model. Модель делегата соответствует шаблону разработки наблюдателя, который позволяет подписчику зарегистрироваться у поставщика и получать от него уведомления.The delegate model follows the observer design pattern, which enables a subscriber to register with, and receive notifications from a provider. Отправитель события отправляет уведомление о событии, а приемник событий получает уведомление и определяет ответ на него.An event sender pushes a notification that an event has happened, and an event receiver receives that notification and defines a response to it. В этом разделе описываются основные компоненты модели делегата, использование событий в приложениях и реализация событий в коде.This article describes the major components of the delegate model, how to consume events in applications, and how to implement events in your code.

Дополнительные сведения об обработке событий в приложениях Магазина Windows 8.x см. в разделе Общие сведения о событиях и перенаправленных событиях.For information about handling events in Windows 8.x Store apps, see Events and routed events overview.

СобытияEvents

Событие — это сообщение, посланное объектом, чтобы сообщить о совершении действия.An event is a message sent by an object to signal the occurrence of an action. Это действие может быть вызвано взаимодействием с пользователем, например при нажатии кнопки, или другой логикой программы, например изменением значения свойства.The action could be caused by user interaction, such as a button click, or it could be raised by some other program logic, such as changing a property’s value. Объект, вызывающий событие, называется отправителем событий.The object that raises the event is called the event sender. Отправителю событий не известен объект или метод, который будет получать (обрабатывать) созданные им события.The event sender doesn't know which object or method will receive (handle) the events it raises. Обычно событие является членом отправителя событий; например, событие Click — член класса Button, а событие PropertyChanged — член класса, реализующего интерфейс INotifyPropertyChanged.The event is typically a member of the event sender; for example, the Click event is a member of the Button class, and the PropertyChanged event is a member of the class that implements the INotifyPropertyChanged interface.

Чтобы определить событие, необходимо использовать ключевое слово event (в C#) или Event (в Visual Basic) в сигнатуре класса события и задать тип делегата для события.To define an event, you use the event (in C#) or Event (in Visual Basic) keyword in the signature of your event class, and specify the type of delegate for the event. Делегаты описаны в следующем разделе.Delegates are described in the next section.

Как правило, для вызова события добавляется метод, помеченный как protected и virtual (в C#) или Protected и Overridable (в Visual Basic).Typically, to raise an event, you add a method that is marked as protected and virtual (in C#) or Protected and Overridable (in Visual Basic). Назовите этот метод OnEventName; например, OnDataReceived.Name this method OnEventName; for example, OnDataReceived. Метод должен принимать один параметр, который определяет объект данных события.The method should take one parameter that specifies an event data object. Этот метод предоставляется, чтобы производные классы могли переопределять логику для вызова события.You provide this method to enable derived classes to override the logic for raising the event. Производный класс должен вызывать метод OnEventName базового класса, чтобы зарегистрированные делегаты получили событие.A derived class should always call the OnEventName method of the base class to ensure that registered delegates receive the event.

В следующем примере показан способ объявления события ThresholdReached.The following example shows how to declare an event named ThresholdReached. Событие связано с делегатом EventHandler и возникает в методе OnThresholdReached.The event is associated with the EventHandler delegate and raised in a method named OnThresholdReached.

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached;
        if (handler != null)
        {
            handler(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

ДелегатыDelegates

Делегат — это тип, содержащий ссылку на метод.A delegate is a type that holds a reference to a method. Делегат объявлен с сигнатурой, указывающей тип возвращаемого значения и параметры для методов, на которые он ссылается, и может содержать ссылки только на методы, соответствующие его сигнатуре.A delegate is declared with a signature that shows the return type and parameters for the methods it references, and can hold references only to methods that match its signature. Таким образом, делегат эквивалентен указателю на строго типизированную функцию или обратному вызову.A delegate is thus equivalent to a type-safe function pointer or a callback. Объявления делегата достаточно для определения класса делегата.A delegate declaration is sufficient to define a delegate class.

Делегаты имеют множество применений в платформе .NET Framework.Delegates have many uses in the .NET Framework. В контексте событий делегат — это посредник (или механизм, подобный указателю) между источником события и кодом, обрабатывающим событие.In the context of events, a delegate is an intermediary (or pointer-like mechanism) between the event source and the code that handles the event. Делегат связывается с событием за счет включения типа делегата в объявление события, как показано в примере в предыдущем разделе.You associate a delegate with an event by including the delegate type in the event declaration, as shown in the example in the previous section. Дополнительные сведения о делегатах см. в разделе, посвященном классу Delegate.For more information about delegates, see the Delegate class.

Платформа .NET Framework предоставляет делегаты EventHandler и EventHandler<TEventArgs> для поддержки большинства сценариев событий.The .NET Framework provides the EventHandler and EventHandler<TEventArgs> delegates to support most event scenarios. Используйте делегат EventHandler для всех событий, не содержащих данных.Use the EventHandler delegate for all events that do not include event data. Используйте делегат EventHandler<TEventArgs> для событий, содержащих данные о событии.Use the EventHandler<TEventArgs> delegate for events that include data about the event. У этих делегатов нет типа возвращаемого значения, они принимают 2 параметра (объект для источника события и объект для данных события).These delegates have no return type value and take two parameters (an object for the source of the event and an object for event data).

Эти делегаты являются многоадресными, то есть могут хранить ссылки на несколько методов обработки событий.Delegates are multicast, which means that they can hold references to more than one event-handling method. Дополнительные сведения см. на справочной странице класса Delegate.For details, see the Delegate reference page. Делегаты позволяют гибко и точно управлять обработкой событий.Delegates provide flexibility and fine-grained control in event handling. Делегат выступает как диспетчер событий для класса, вызывающий событие за счет ведения списка зарегистрированных обработчиков для события.A delegate acts as an event dispatcher for the class that raises the event by maintaining a list of registered event handlers for the event.

Для сценариев, в которых делегаты EventHandler и EventHandler<TEventArgs> не работают, можно определить собственный делегат.For scenarios where the EventHandler and EventHandler<TEventArgs> delegates do not work, you can define a delegate. Сценарии, для которых необходимо определять собственные делегаты, очень редки. Это бывает, например, при работе с кодом, не распознающим универсальные типы.Scenarios that require you to define a delegate are very rare, such as when you must work with code that does not recognize generics. При объявлении делегат необходимо пометить ключевым словом delegate (в C#) или Delegate (в Visual Basic).You mark a delegate with the delegate (in C#) and Delegate (in Visual Basic) keyword in the declaration. В следующем примере показано, как объявить делегат с именем ThresholdReachedEventHandler.The following example shows how to declare a delegate named ThresholdReachedEventHandler.

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

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

Данные, связанные с событием, могут быть предоставлены с помощью класса данных события.Data that is associated with an event can be provided through an event data class. Платформа .NET Framework предоставляет множество классов данных событий, которые можно использовать в приложениях.The .NET Framework provides many event data classes that you can use in your applications. Например, класс SerialDataReceivedEventArgs — класс данных события SerialPort.DataReceived.For example, the SerialDataReceivedEventArgs class is the event data class for the SerialPort.DataReceived event. В платформе .NET Framework имена всех классов данных событий оканчиваются ключевым словом EventArgs.The .NET Framework follows a naming pattern of ending all event data classes with EventArgs. Определить, какой класс данных события связан с событием, можно по делегату этого события.You determine which event data class is associated with an event by looking at the delegate for the event. Например, делегат SerialDataReceivedEventHandler содержит класс SerialDataReceivedEventArgs в качестве одного из своих параметров.For example, the SerialDataReceivedEventHandler delegate includes the SerialDataReceivedEventArgs class as one of its parameters.

Класс EventArgs является базовым типом для всех классов данных событий.The EventArgs class is the base type for all event data classes. Класс EventArgs используется также, если событие не содержит связанных данных.EventArgs is also the class you use when an event does not have any data associated with it. При создании события, которое лишь уведомляет другие классы о том, что что-то произошло, и не передает никаких данных, используйте класс EventArgs в качестве второго параметра в делегате.When you create an event that is only meant to notify other classes that something happened and does not need to pass any data, include the EventArgs class as the second parameter in the delegate. Если данные не предоставляются, можно передать значение EventArgs.Empty.You can pass the EventArgs.Empty value when no data is provided. Делегат EventHandler содержит класс EventArgs в качестве параметра.The EventHandler delegate includes the EventArgs class as a parameter.

Если требуется создать пользовательский класс данных события, создайте класс, производный от класса EventArgs, а затем укажите все члены, необходимые для передачи данных, связанных с событием.When you want to create a customized event data class, create a class that derives from EventArgs, and then provide any members needed to pass data that is related to the event. В большинстве случаев следует использовать схему именования .NET Framework и завершать имя класса данных события ключевым словом EventArgs.Typically, you should use the same naming pattern as the .NET Framework and end your event data class name with EventArgs.

В следующем примере показан класс данных события с именем ThresholdReachedEventArgs.The following example shows an event data class named ThresholdReachedEventArgs. Он содержит свойства, относящиеся только к вызываемому событию.It contains properties that are specific to the event being raised.

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

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

Для обработки события в приемнике события необходимо определить метод обработчика события.To respond to an event, you define an event handler method in the event receiver. Этот метод должен соответствовать сигнатуре делегата обрабатываемого события.This method must match the signature of the delegate for the event you are handling. В обработчике событий выполняются действия, необходимые при возникновении события, например сбор данных, введенных пользователем при нажатии кнопки.In the event handler, you perform the actions that are required when the event is raised, such as collecting user input after the user clicks a button. Чтобы получать уведомления при возникновении события, метод обработчика события должен быть подписан на событие.To receive notifications when the event occurs, your event handler method must subscribe to the event.

В следующем примере показан метод обработчика события c_ThresholdReached, который соответствует сигнатуре делегата EventHandler.The following example shows an event handler method named c_ThresholdReached that matches the signature for the EventHandler delegate. Метод подписывается на событие ThresholdReached.The method subscribes to the ThresholdReached event.

class Program
{
    static void Main(string[] args)
    {
        Counter 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 Counter = 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

Обработчики статических и динамических событийStatic and Dynamic Event Handlers

Платформа .NET Framework позволяет подписчикам регистрироваться на уведомления о событиях как статически, так и динамически.The .NET Framework allows subscribers to register for event notifications either statically or dynamically. Обработчики статических событий действуют в течение всего жизненного цикла класса, события которого они обрабатывают.Static event handlers are in effect for the entire life of the class whose events they handle. Обработчики динамических событий активируются и деактивируются во время выполнения программы, обычно в ответ на определенную условную логику программы.Dynamic event handlers are explicitly activated and deactivated during program execution, usually in response to some conditional program logic. Например, они могут использоваться, если уведомления о событиях требуются только в определенных условиях, либо приложение предоставляет несколько обработчиков событий и выбор конкретного обработчика зависит от условий среды выполнения.For example, they can be used if event notifications are needed only under certain conditions or if an application provides multiple event handlers and run-time conditions define the appropriate one to use. В примере в предыдущем разделе показано, как динамически добавлять обработчик события.The example in the previous section shows how to dynamically add an event handler. Дополнительные сведения см. в разделах события (в Visual Basic) и события (в C#).For more information, see Events (in Visual Basic) and Events (in C#).

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

Если класс создает несколько событий, компилятор создает одно поле для каждого экземпляра делегата события.If your class raises multiple events, the compiler generates one field per event delegate instance. При большом количестве событий стоимость хранения одного поля на делегата может оказаться неприемлемой.If the number of events is large, the storage cost of one field per delegate may not be acceptable. Для таких случаев в платформе .NET Framework предоставляются свойства события, которые можно использовать вместе с другой структурой данных для хранения делегатов события.For those situations, the .NET Framework provides event properties that you can use with another data structure of your choice to store event delegates.

Свойства событий состоят из объявлений событий и методов доступа к событиям.Event properties consist of event declarations accompanied by event accessors. Методы доступа к событиям — это определяемые пользователем методы, добавляющие или удаляющие экземпляры делегата события из структуры данных хранения.Event accessors are methods that you define to add or remove event delegate instances from the storage data structure. Обратите внимание, что использование свойств события снижает быстродействие по сравнению с полями события, поскольку перед вызовом каждого делегата события его необходимо извлечь.Note that event properties are slower than event fields, because each event delegate must be retrieved before it can be invoked. Необходимо найти компромисс между памятью и скоростью.The trade-off is between memory and speed. Если ваш класс определяет много событий, которые вызываются нечасто, необходимо реализовать свойства событий.If your class defines many events that are infrequently raised, you will want to implement event properties. Дополнительные сведения см. в разделе Как Обработка нескольких событий с помощью их свойств.For more information, see How to: Handle Multiple Events Using Event Properties.

ЗаголовокTitle ОписаниеDescription
Практическое руководство. Вызов и прием событийHow to: Raise and Consume Events Содержит примеры вызова и приема событий.Contains examples of raising and consuming events.
Практическое руководство. Обработка нескольких событий с помощью их свойствHow to: Handle Multiple Events Using Event Properties Показывает, как использовать свойства событий для обработки нескольких событий.Shows how to use event properties to handle multiple events.
Шаблон разработки наблюдателяObserver Design Pattern Описывает шаблон разработки, позволяющий подписчику зарегистрироваться у поставщика и получать от него уведомления.Describes the design pattern that enables a subscriber to register with, and receive notifications from, a provider.
Практическое руководство. Прием событий в приложениях веб-формHow to: Consume Events in a Web Forms Application Описывает способы обработки событий, вызванных элементом управления веб-форм (Web Forms).Shows how to handle an event that is raised by a Web Forms control.

См. такжеSee also