Obsługa i zgłaszanie zdarzeń

Zdarzenia na platformie .NET są oparte na modelu delegata. Model delegata jest zgodny ze wzorcem projektowania obserwatora, który umożliwia subskrybentowi zarejestrowanie się w usłudze i odbieranie powiadomień od dostawcy. Nadawca zdarzeń wypycha powiadomienie o tym, że wystąpiło zdarzenie, a odbiorca zdarzeń odbiera to powiadomienie i definiuje odpowiedź na nie. W tym artykule opisano główne składniki modelu delegata, sposób korzystania z zdarzeń w aplikacjach oraz sposób implementowania zdarzeń w kodzie.

Zdarzenia

Zdarzenie jest komunikatem wysyłanym przez obiekt, aby zasygnalizować wystąpienie akcji. Akcja może być spowodowana interakcją użytkownika, taką jak kliknięcie przycisku, lub może wynikać z innej logiki programu, takiej jak zmiana wartości właściwości. Obiekt, który zgłasza zdarzenie, jest nazywany nadawcą zdarzeń. Nadawca zdarzeń nie wie, który obiekt lub metoda otrzymają (obsłużyć) zdarzenia, które zgłasza. Zdarzenie jest zazwyczaj członkiem nadawcy zdarzeń; na przykład Click zdarzenie jest elementem członkowskim Button klasy, a PropertyChanged zdarzenie jest elementem członkowskim klasy, która implementuje INotifyPropertyChanged interfejs.

Aby zdefiniować zdarzenie, należy użyć słowa kluczowego C# event lub Visual Basic Event w podpisie klasy zdarzeń i określić typ delegata zdarzenia. Delegaci są opisywani w następnej sekcji.

Zazwyczaj w celu wywołania zdarzenia należy dodać metodę oznaczoną jako protected i virtual (w języku C#) lub ProtectedOverridable (w Visual Basic). Nadaj tej metodzie nazwę OnEventName, na przykład OnDataReceived. Metoda powinna przyjmować jeden parametr określający obiekt danych zdarzenia, który jest obiektem typu EventArgs lub typem pochodnym. Ta metoda umożliwia klasom pochodnym zastąpienie logiki w celu podniesienia zdarzenia. Klasa pochodna powinna zawsze wywoływać metodę OnEventName klasy bazowej, aby upewnić się, że zarejestrowani delegaci otrzymają zdarzenie.

W poniższym przykładzie pokazano, jak zadeklarować zdarzenie o nazwie ThresholdReached. Zdarzenie jest skojarzone z delegatem EventHandler i wywoływane w metodzie o nazwie 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

Delegaci

Delegat to typ, który zawiera odwołanie do metody. Delegat jest zadeklarowany z podpisem, który pokazuje zwracany typ i parametry dla metod, do których się odwołuje, i może przechowywać odwołania tylko do metod pasujących do podpisu. Delegat jest zatem odpowiednikiem wskaźnika funkcji bezpiecznej typu lub wywołania zwrotnego. Deklaracja delegata jest wystarczająca do zdefiniowania klasy delegata.

Delegaci mają wiele zastosowań na platformie .NET. W kontekście zdarzeń delegat jest pośrednikiem (lub mechanizmem przypominającym wskaźnik) między źródłem zdarzeń a kodem obsługującym zdarzenie. Delegat jest skojarzony z zdarzeniem, uwzględniając typ delegata w deklaracji zdarzenia, jak pokazano w przykładzie w poprzedniej sekcji. Aby uzyskać więcej informacji na temat delegatów, zobacz klasę Delegate .

Platforma .NET udostępnia EventHandler delegatów i EventHandler<TEventArgs> do obsługi większości scenariuszy zdarzeń. Użyj delegata EventHandler dla wszystkich zdarzeń, które nie zawierają danych zdarzeń. Użyj delegata EventHandler<TEventArgs> dla zdarzeń zawierających dane o zdarzeniu. Ci delegaci nie mają wartości typu zwracanego i przyjmują dwa parametry (obiekt dla źródła zdarzenia i obiekt danych zdarzenia).

Delegaci to multiemisji, co oznacza, że mogą przechowywać odwołania do więcej niż jednej metody obsługi zdarzeń. Aby uzyskać szczegółowe informacje, zobacz stronę referencyjną Delegate . Delegaty zapewniają elastyczność i szczegółową kontrolę w obsłudze zdarzeń. Delegat pełni rolę dyspozytora zdarzeń dla klasy, która zgłasza zdarzenie, utrzymując listę zarejestrowanych programów obsługi zdarzeń dla zdarzenia.

W przypadku scenariuszy, w których EventHandler delegaty i EventHandler<TEventArgs> nie działają, można zdefiniować delegata. Scenariusze, które wymagają zdefiniowania delegata, są bardzo rzadkie, takie jak kiedy trzeba pracować z kodem, który nie rozpoznaje typów ogólnych. W deklaracji oznaczysz delegata za pomocą języka C# delegate i Visual Basic Delegate słowa kluczowego. W poniższym przykładzie pokazano, jak zadeklarować delegata o nazwie ThresholdReachedEventHandler.

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

Dane zdarzenia

Dane skojarzone ze zdarzeniem mogą być udostępniane za pośrednictwem klasy danych zdarzenia. Platforma .NET udostępnia wiele klas danych zdarzeń, których można używać w aplikacjach. Na przykład SerialDataReceivedEventArgs klasa to klasa danych zdarzenia dla SerialPort.DataReceived zdarzenia. Platforma .NET jest zgodna ze wzorcem nazewnictwa kończącym wszystkie klasy danych zdarzeń przy użyciu polecenia EventArgs. Określasz, która klasa danych zdarzeń jest skojarzona z zdarzeniem, przeglądając delegata zdarzenia. Na przykład SerialDataReceivedEventHandler delegat zawiera klasę SerialDataReceivedEventArgs jako jeden z jego parametrów.

Klasa EventArgs jest typem podstawowym dla wszystkich klas danych zdarzeń. EventArgs jest również klasą używaną, gdy zdarzenie nie ma żadnych skojarzonych z nim danych. Podczas tworzenia zdarzenia, które jest przeznaczone tylko do powiadamiania innych klas, że coś się stało i nie musi przekazywać żadnych danych, dołącz klasę EventArgs jako drugi parametr w delegatu. Możesz przekazać wartość, EventArgs.Empty gdy nie podano żadnych danych. Delegat EventHandler zawiera klasę EventArgs jako parametr.

Jeśli chcesz utworzyć niestandardową klasę danych zdarzeń, utwórz klasę pochodzącą z EventArgsklasy , a następnie podaj wszystkie elementy członkowskie potrzebne do przekazania danych powiązanych ze zdarzeniem. Zazwyczaj należy użyć tego samego wzorca nazewnictwa co platforma .NET i zakończyć nazwę klasy danych zdarzenia za pomocą polecenia EventArgs.

W poniższym przykładzie przedstawiono klasę danych zdarzenia o nazwie ThresholdReachedEventArgs. Zawiera właściwości specyficzne dla zgłaszanego zdarzenia.

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

Procedury obsługi zdarzeń

Aby odpowiedzieć na zdarzenie, należy zdefiniować metodę obsługi zdarzeń w odbiorniku zdarzeń. Ta metoda musi być zgodna z podpisem delegata dla zdarzenia, które obsługujesz. W procedurze obsługi zdarzeń wykonujesz akcje wymagane podczas wywoływanego zdarzenia, takie jak zbieranie danych wejściowych użytkownika po kliknięciu przycisku przez użytkownika. Aby otrzymywać powiadomienia po wystąpieniu zdarzenia, metoda obsługi zdarzeń musi subskrybować zdarzenie.

W poniższym przykładzie przedstawiono metodę obsługi zdarzeń o nazwie c_ThresholdReached zgodną z podpisem delegata EventHandler . Metoda subskrybuje ThresholdReached zdarzenie.

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

Programy obsługi zdarzeń statycznych i dynamicznych

Platforma .NET umożliwia subskrybentom rejestrowanie się w celu otrzymywania powiadomień o zdarzeniach statycznie lub dynamicznie. Statyczne programy obsługi zdarzeń są obowiązujące dla całej klasy, której zdarzenia obsługują. Dynamiczne programy obsługi zdarzeń są jawnie aktywowane i dezaktywowane podczas wykonywania programu, zwykle w odpowiedzi na pewną logikę programu warunkowego. Można ich na przykład użyć, jeśli powiadomienia o zdarzeniach są potrzebne tylko w określonych warunkach lub jeśli aplikacja udostępnia wiele procedur obsługi zdarzeń i warunków czasu wykonywania definiują odpowiednie do użycia. W przykładzie w poprzedniej sekcji pokazano, jak dynamicznie dodać procedurę obsługi zdarzeń. Aby uzyskać więcej informacji, zobacz Zdarzenia (w Visual Basic) i Zdarzenia (w języku C#).

Podnoszenie wielu zdarzeń

Jeśli klasa zgłasza wiele zdarzeń, kompilator generuje jedno pole na wystąpienie delegata zdarzeń. Jeśli liczba zdarzeń jest duża, koszt magazynowania jednego pola na delegata może nie być akceptowalny. W takich sytuacjach platforma .NET udostępnia właściwości zdarzeń, których można użyć z inną wybraną strukturą danych do przechowywania delegatów zdarzeń.

Właściwości zdarzenia składają się z deklaracji zdarzeń towarzyszących akcesorom zdarzeń. Metody dostępu do zdarzeń to metody zdefiniowane do dodawania lub usuwania wystąpień delegatów zdarzeń ze struktury danych magazynu. Należy pamiętać, że właściwości zdarzeń są wolniejsze niż pola zdarzeń, ponieważ każdy delegat zdarzenia musi zostać pobrany, zanim będzie można go wywołać. Kompromis jest między pamięcią a szybkością. Jeśli klasa definiuje wiele zdarzeń, które są często zgłaszane, należy zaimplementować właściwości zdarzeń. Aby uzyskać więcej informacji, zobacz Instrukcje: obsługa wielu zdarzeń przy użyciu właściwości zdarzeń.

Tytuł Opis
Porady: wywoływanie zdarzeń i korzystanie z nich Zawiera przykłady zgłaszania i używania zdarzeń.
Instrukcje: Obsługa wielu zdarzeń przy użyciu właściwości zdarzenia Pokazuje, jak używać właściwości zdarzeń do obsługi wielu zdarzeń.
Wzorzec projektu obserwatora Opisuje wzorzec projektu, który umożliwia subskrybentowi zarejestrowanie się i odbieranie powiadomień od dostawcy.

Zobacz też