Hantera och generera händelser

Händelser i .NET baseras på ombudsmodellen. Ombudsmodellen följer mönstret för observatörsdesign, vilket gör det möjligt för en prenumerant att registrera sig med och ta emot meddelanden från en leverantör. En händelseavsändare skickar ett meddelande om att en händelse har inträffat och en händelsemottagare tar emot det meddelandet och definierar ett svar på den. Den här artikeln beskriver huvudkomponenterna i ombudsmodellen, hur du använder händelser i program och hur du implementerar händelser i koden.

Händelser

En händelse är ett meddelande som skickas av ett objekt för att signalera förekomsten av en åtgärd. Åtgärden kan orsakas av användarinteraktion, till exempel ett knappklick, eller på grund av annan programlogik, till exempel att ändra en egenskaps värde. Objektet som genererar händelsen kallas händelsesändare. Händelsesändaren vet inte vilket objekt eller vilken metod som ska ta emot (hantera) de händelser som genereras. Händelsen är vanligtvis medlem i händelsesändaren. Händelsen är till exempel Click medlem i Button klassen och PropertyChanged händelsen är medlem i klassen som implementerar INotifyPropertyChanged gränssnittet.

Om du vill definiera en händelse använder du nyckelordet C# event eller Visual Basic Event i signaturen för händelseklassen och anger typen av ombud för händelsen. Ombud beskrivs i nästa avsnitt.

För att skapa en händelse lägger du vanligtvis till en metod som är markerad som protected och virtual (i C#) eller Protected (Overridablei Visual Basic). Ge den här metoden On namnet EventName, till exempel OnDataReceived. Metoden ska ta en parameter som anger ett händelsedataobjekt, som är ett objekt av typen EventArgs eller en härledd typ. Du anger den här metoden för att aktivera härledda klasser för att åsidosätta logiken för att höja händelsen. En härledd klass ska alltid anropa Onmetoden EventName för basklassen för att säkerställa att registrerade ombud tar emot händelsen.

I följande exempel visas hur du deklarerar en händelse med namnet ThresholdReached. Händelsen är associerad med ombudet EventHandler och genereras i en metod med namnet 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

Delegeringar

Ett ombud är en typ som innehåller en referens till en metod. Ett ombud deklareras med en signatur som visar returtypen och parametrarna för de metoder som den refererar till, och den kan endast innehålla referenser till metoder som matchar dess signatur. Ett ombud motsvarar alltså en typsäker funktionspekare eller ett återanrop. En ombudsdeklaration räcker för att definiera en ombudsklass.

Ombud har många användningsområden i .NET. I händelsesammanhang är ett ombud en mellanhand (eller pekarliknande mekanism) mellan händelsekällan och koden som hanterar händelsen. Du associerar ett ombud med en händelse genom att inkludera ombudstypen i händelsedeklarationen, som du ser i exemplet i föregående avsnitt. Mer information om ombud finns i Delegate klassen .

.NET tillhandahåller ombuden EventHandler och EventHandler<TEventArgs> för att stödja de flesta händelsescenarier. Använd ombudet EventHandler för alla händelser som inte innehåller händelsedata. Använd ombudet EventHandler<TEventArgs> för händelser som innehåller data om händelsen. Dessa ombud har inget returtypvärde och tar två parametrar (ett objekt för händelsens källa och ett objekt för händelsedata).

Ombud är multicast, vilket innebär att de kan innehålla referenser till mer än en händelsehanteringsmetod. Mer information finns på Delegate referenssidan. Ombud ger flexibilitet och detaljerad kontroll vid händelsehantering. Ett ombud fungerar som händelseutskickare för klassen som genererar händelsen genom att upprätthålla en lista över registrerade händelsehanterare för händelsen.

För scenarier där ombuden EventHandler och EventHandler<TEventArgs> inte fungerar kan du definiera ett ombud. Scenarier som kräver att du definierar ett ombud är mycket sällsynta, till exempel när du måste arbeta med kod som inte känner igen generiska objekt. Du markerar ett ombud med nyckelordet C# delegate och Visual Basic Delegate i deklarationen. I följande exempel visas hur du deklarerar ett ombud med namnet ThresholdReachedEventHandler.

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

Händelsedata

Data som är associerade med en händelse kan tillhandahållas via en händelsedataklass. .NET tillhandahåller många händelsedataklasser som du kan använda i dina program. Klassen är till exempel SerialDataReceivedEventArgs händelsedataklassen SerialPort.DataReceived för händelsen. .NET följer ett namngivningsmönster för att avsluta alla händelsedataklasser med EventArgs. Du avgör vilken händelsedataklass som är associerad med en händelse genom att titta på ombudet för händelsen. Ombudet SerialDataReceivedEventHandler inkluderar SerialDataReceivedEventArgs till exempel klassen som en av dess parametrar.

Klassen EventArgs är bastypen för alla händelsedataklasser. EventArgs är också den klass som du använder när en händelse inte har några associerade data. När du skapar en händelse som bara är avsedd att meddela andra klasser om att något har hänt och inte behöver skicka några data, inkluderar du EventArgs klassen som den andra parametern i ombudet. Du kan skicka värdet EventArgs.Empty när inga data anges. Ombudet EventHandlerEventArgs innehåller klassen som en parameter.

När du vill skapa en anpassad händelsedataklass skapar du en klass som härleds från EventArgsoch anger sedan alla medlemmar som behövs för att skicka data som är relaterade till händelsen. Vanligtvis bör du använda samma namngivningsmönster som .NET och avsluta händelsedataklassnamnet med EventArgs.

I följande exempel visas en händelsedataklass med namnet ThresholdReachedEventArgs. Den innehåller egenskaper som är specifika för händelsen som genereras.

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

Händelsehanterare

För att svara på en händelse definierar du en händelsehanterarmetod i händelsemottagaren. Den här metoden måste matcha signaturen för ombudet för den händelse som du hanterar. I händelsehanteraren utför du de åtgärder som krävs när händelsen aktiveras, till exempel samla in användarindata när användaren har klickat på en knapp. Om du vill ta emot meddelanden när händelsen inträffar måste händelsehanterarmetoden prenumerera på händelsen.

I följande exempel visas en händelsehanterarmetod med namnet c_ThresholdReached som matchar ombudets EventHandler signatur. Metoden prenumererar på ThresholdReached händelsen.

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

Statiska och dynamiska händelsehanterare

Med .NET kan prenumeranter registrera sig för händelsemeddelanden statiskt eller dynamiskt. Statiska händelsehanterare gäller under hela klassens livslängd vars händelser de hanterar. Dynamiska händelsehanterare aktiveras och inaktiveras uttryckligen under programkörning, vanligtvis som svar på viss logik för villkorsstyrda program. De kan till exempel användas om händelsemeddelanden endast behövs under vissa villkor eller om ett program tillhandahåller flera händelsehanterare och körningsvillkor definierar den lämpliga som ska användas. Exemplet i föregående avsnitt visar hur du dynamiskt lägger till en händelsehanterare. Mer information finns i Händelser (i Visual Basic) och Händelser (i C#).

Skapa flera händelser

Om klassen genererar flera händelser genererar kompilatorn ett fält per händelsedelegatinstans. Om antalet händelser är stort kanske lagringskostnaden för ett fält per ombud inte är acceptabel. För dessa situationer tillhandahåller .NET händelseegenskaper som du kan använda med en annan datastruktur som du väljer för att lagra händelsedelegater.

Händelseegenskaper består av händelsedeklarationer tillsammans med händelseåtkomster. Händelseåtkomster är metoder som du definierar för att lägga till eller ta bort händelsedelegatinstanser från lagringsdatastrukturen. Observera att händelseegenskaperna är långsammare än händelsefälten, eftersom varje händelsedelegat måste hämtas innan den kan anropas. Kompromissen är mellan minne och hastighet. Om klassen definierar många händelser som sällan aktiveras vill du implementera händelseegenskaper. Mer information finns i Så här hanterar du flera händelser med hjälp av händelseegenskaper.

Rubrik Beskrivning
Anvisningar: Skapa och använda händelser Innehåller exempel på att höja och använda händelser.
Anvisningar: Hantera flera händelser med hjälp av händelseegenskaper Visar hur du använder händelseegenskaper för att hantera flera händelser.
Designmönster för övervakare Beskriver designmönstret som gör det möjligt för en prenumerant att registrera sig med och ta emot meddelanden från en provider.

Se även