Zoeken…


Invoering

Een gebeurtenis is een melding dat er iets is gebeurd (zoals een muisklik) of, in sommige gevallen, staat op het punt te gebeuren (zoals een prijsverandering).

Klassen kunnen gebeurtenissen definiëren en hun instanties (objecten) kunnen deze gebeurtenissen verhogen. Een knop kan bijvoorbeeld een Click-gebeurtenis bevatten die wordt gegenereerd wanneer een gebruiker erop heeft geklikt.

Gebeurtenishandlers zijn dan methoden die worden aangeroepen wanneer hun bijbehorende gebeurtenis wordt verhoogd. Een formulier kan bijvoorbeeld een Clicked-gebeurtenishandler voor elke knop bevatten.

parameters

Parameter Details
EventArgsT Het type dat is afgeleid van EventArgs en de gebeurtenisparameters bevat.
Evenement naam De naam van het evenement.
handlerName De naam van de gebeurtenishandler.
SenderObject Het object dat de gebeurtenis aanroept.
EventArguments Een exemplaar van het type EventArgsT dat de gebeurtenisparameters bevat.

Opmerkingen

Bij het organiseren van een evenement:

  • Controleer altijd of de gemachtigde null . Een nulafgevaardigde betekent dat het evenement geen abonnees heeft. Het verhogen van een evenement zonder abonnees resulteert in een NullReferenceException .
6.0
  • Kopieer de gedelegeerde (bijv. EventName ) naar een lokale variabele (bijv. eventName ) voordat u op nul controleert / de gebeurtenis verhoogt. Dit vermijdt race-omstandigheden in multi-threaded omgevingen:

Fout :

    if(Changed != null)      // Changed has 1 subscriber at this point
                             // In another thread, that one subscriber decided to unsubscribe
        Changed(this, args); // `Changed` is now null, `NullReferenceException` is thrown.

Rechts :

    // Cache the "Changed" event as a local. If it is not null, then use
    // the LOCAL variable (handler) to raise the event, NOT the event itself.
    var handler = Changed;
    if(handler != null)
        handler(this, args);
6.0
  • Gebruik de null-voorwaardelijke operator (?.) Om de methode te verhogen in plaats van de gedelegeerde op subscribers te controleren op een if instructie: EventName?.Invoke(SenderObject, new EventArgsT());
  • Wanneer u Action <> gebruikt om gedelegeerde typen te declareren, moet de handtekening van de anonieme methode / gebeurtenis-handler hetzelfde zijn als het gedeclareerde anonieme gedelegeerde type in de gebeurtenisverklaring.

Gebeurtenissen melden en verhogen

Evenement melden

Je kunt een evenement voor elke class of struct aangeven met de volgende syntaxis:

public class MyClass
{
    // Declares the event for MyClass
    public event EventHandler MyEvent;

    // Raises the MyEvent event
    public void RaiseEvent()
    {
        OnMyEvent();
    }
}    

Er is een uitgebreide syntaxis voor het declareren van evenementen, waarbij u een privé-exemplaar van het evenement bezit en een openbaar exemplaar definieert met behulp van add en set accessors. De syntaxis lijkt erg op C # -eigenschappen. In alle gevallen verdient de hierboven getoonde syntaxis de voorkeur, omdat de compiler code uitzendt om ervoor te zorgen dat meerdere threads veilig event-handlers kunnen toevoegen aan en verwijderen uit de event in uw klas.

Het evenement verhogen

6.0
private void OnMyEvent()
{
    EventName?.Invoke(this, EventArgs.Empty); 
}
6.0
private void OnMyEvent()
{
    // Use a local for EventName, because another thread can modify the
    // public EventName between when we check it for null, and when we
    // raise the event.
    var eventName = EventName;

    // If eventName == null, then it means there are no event-subscribers,
    // and therefore, we cannot raise the event.
    if(eventName != null)
        eventName(this, EventArgs.Empty);

}

Houd er rekening mee dat evenementen alleen kunnen worden verhoogd door het type aangifte. Klanten kunnen zich alleen inschrijven / afmelden.

Voor C # -versies vóór 6.0, waarbij EventName?.Invoke niet wordt ondersteund, is het een goede gewoonte om de gebeurtenis vóór een aanroep aan een tijdelijke variabele toe te wijzen, zoals in het voorbeeld wordt getoond, wat zorgt voor thread-veiligheid in gevallen waarin meerdere threads hetzelfde uitvoeren code. Als u dit niet doet, kan een NullReferenceException worden gegenereerd in bepaalde gevallen waarin meerdere threads dezelfde objectinstantie gebruiken. In C # 6.0 zendt de compiler code uit die lijkt op die in het codevoorbeeld voor C # 6.

Standaard evenementverklaring

Evenementverklaring:

public event EventHandler<EventArgsT> EventName;

Verklaring gebeurtenisbehandelaar:

public void HandlerName(object sender, EventArgsT args) { /* Handler logic */ }

Abonneren op het evenement:

dynamisch:

EventName += HandlerName;

Via de ontwerper:

  1. Klik op de knop Gebeurtenissen in het eigenschappenvenster van het besturingselement (bliksemschicht)
  2. Dubbelklik op de naam van het evenement:

voer hier de afbeeldingsbeschrijving in

  1. Visual Studio genereert de gebeurteniscode:
private void Form1_Load(object sender, EventArgs e)
{

}

De methode aanroepen:

EventName(SenderObject, EventArguments);

Anonieme evenementafhandelingsverklaring

Evenementverklaring:

public event EventHandler<EventArgsType> EventName;

Gebeurtenis-afhandelingsverklaring met lambda-operator => en inschrijvend op de gebeurtenis:

EventName += (obj, eventArgs) => { /* Handler logic */ };

Declaratie van gebeurtenishandler met syntaxis van de gemachtigde anonieme methode:

EventName += delegate(object obj, EventArgsType eventArgs) { /* Handler Logic */ };

Verklaring en abonnement van een gebeurtenishandler die de parameter van de gebeurtenis niet gebruikt, en dus de bovenstaande syntaxis kan gebruiken zonder parameters op te geven:

EventName += delegate { /* Handler Logic */ }

Het evenement oproepen:

EventName?.Invoke(SenderObject, EventArguments);

Niet-standaard evenementverklaring

Evenementen kunnen van elk type gedelegeerde zijn, niet alleen EventHandler en EventHandler<T> . Bijvoorbeeld:

//Declaring an event
public event Action<Param1Type, Param2Type, ...> EventName;

Dit wordt op dezelfde manier gebruikt als standaard EventHandler evenementen:

//Adding a named event handler
public void HandlerName(Param1Type parameter1, Param2Type parameter2, ...) {
    /* Handler logic */
}
EventName += HandlerName;

//Adding an anonymous event handler
EventName += (parameter1, parameter2, ...) => { /* Handler Logic */ };

//Invoking the event
EventName(parameter1, parameter2, ...);

Het is mogelijk om meerdere gebeurtenissen van hetzelfde type in een enkele instructie te declareren, vergelijkbaar met velden en lokale variabelen (hoewel dit vaak een slecht idee is):

public event EventHandler Event1, Event2, Event3;

Dit verklaart drie afzonderlijke evenementen ( Event1 , Event2 en Event3 ) van het type EventHandler .
Opmerking: hoewel sommige compilers deze syntaxis zowel in interfaces als in klassen accepteren, biedt de C # -specificatie (v5.0 §13.2.3) grammatica voor interfaces die dit niet toestaan, dus het gebruik hiervan in interfaces kan onbetrouwbaar zijn met verschillende compilers.

Aangepaste EventArgs maken met extra gegevens

Aangepaste gebeurtenissen hebben meestal aangepaste gebeurtenisargumenten nodig die informatie over de gebeurtenis bevatten. MouseEventArgs bijvoorbeeld, dat wordt gebruikt door muisgebeurtenissen zoals MouseDown of MouseUp gebeurtenissen, bevat informatie over Location of Buttons die werden gebruikt om de gebeurtenis te genereren.

Bij het maken van nieuwe evenementen, om een aangepaste gebeurtenis te maken, arg:

  • Maak een klasse die is afgeleid van EventArgs en definieer eigenschappen voor benodigde gegevens.
  • Als conventie moet de naam van de klasse eindigen op EventArgs .

Voorbeeld

In het onderstaande voorbeeld maken we een PriceChangingEventArgs gebeurtenis voor de eigenschap Price van een klasse. De gebeurtenisgegevensklasse bevat een CurrentPrice en een NewPrice . Het evenement wordt georganiseerd wanneer u een nieuwe waarde toekent aan Price , en laat de consument weten dat de waarde verandert en laat hem weten wat de huidige prijs en de nieuwe prijs zijn:

PriceChangingEventArgs

public class PriceChangingEventArgs : EventArgs
{
    public PriceChangingEventArgs(int currentPrice, int newPrice)
    {
        this.CurrentPrice = currentPrice;
        this.NewPrice = newPrice;
    }

    public int CurrentPrice { get; private set; }
    public int NewPrice { get; private set; }
}

Product

public class Product
{
    public event EventHandler<PriceChangingEventArgs> PriceChanging;

    int price;
    public int Price
    {
        get { return price; }
        set
        {
            var e = new PriceChangingEventArgs(price, value);
            OnPriceChanging(e);
            price = value;
        }
    }

    protected void OnPriceChanging(PriceChangingEventArgs e)
    {
        var handler = PriceChanging;
        if (handler != null)
            handler(this, e);
    }
}

U kunt het voorbeeld verbeteren door de consument de nieuwe waarde te laten wijzigen en vervolgens wordt de waarde gebruikt voor eigendom. Om dit te doen is het voldoende om deze wijzigingen in klassen toe te passen.

Wijzig de definitie van NewPrice om instelbaar te zijn:

public int NewPrice { get; set; }

Wijzig de definitie van Price om e.NewPrice te gebruiken als waarde van eigenschap, nadat u OnPriceChanging :

int price;
public int Price
{
    get { return price; }
    set
    {
        var e = new PriceChangingEventArgs(price, value);
        OnPriceChanging(e);
        price = e.NewPrice;
    }
}

Een annuleerbare gebeurtenis maken

Een te annuleren gebeurtenis kan door een klasse worden FormClosing wanneer deze op het punt staat een actie uit te voeren die kan worden geannuleerd, zoals de FormClosing gebeurtenis van een Form .

Om een dergelijk evenement te maken:

  • Maak een nieuwe gebeurtenisarg die is afgeleid van CancelEventArgs en voeg extra eigenschappen toe voor gebeurtenisgegevens.
  • Maak een evenement met behulp van EventHandler<T> en gebruik de nieuwe annuleringsgebeurtenis arg-klasse die u hebt gemaakt.

Voorbeeld

In het onderstaande voorbeeld maken we een PriceChangingEventArgs gebeurtenis voor de eigenschap Price van een klasse. De dataklasse van het evenement bevat een Value die de consument op de hoogte brengt van het nieuwe. De gebeurtenis wordt verhoogd wanneer u een nieuwe waarde toekent aan Price , en laat de consument weten dat de waarde verandert en laat hem de gebeurtenis annuleren. Als de consument het evenement annuleert, wordt de vorige waarde voor Price gebruikt:

PriceChangingEventArgs

public class PriceChangingEventArgs : CancelEventArgs
{
    int value;
    public int Value
    {
        get { return value; }
    }
    public PriceChangingEventArgs(int value)
    {
        this.value = value;
    }
}

Product

public class Product
{
    int price;
    public int Price
    {
        get { return price; }
        set
        {
            var e = new PriceChangingEventArgs(value);
            OnPriceChanging(e);
            if (!e.Cancel)
                price = value;
        }
    }

    public event EventHandler<PriceChangingEventArgs> PropertyChanging;
    protected void OnPriceChanging(PriceChangingEventArgs e)
    {
        var handler = PropertyChanging;
        if (handler != null)
            PropertyChanging(this, e);
    }
}

Evenementeigenschappen

Als een klasse een groot aantal evenementen verhoogt, zijn de opslagkosten van één veld per deelnemer mogelijk niet acceptabel. Het .NET Framework biedt evenementeigenschappen voor deze gevallen. Op deze manier kunt u een andere gegevensstructuur zoals EventHandlerList gebruiken om afgevaardigden van evenementen op te slaan:

public class SampleClass 
{
    // Define the delegate collection.
    protected EventHandlerList eventDelegates = new EventHandlerList();

    // Define a unique key for each event.
    static readonly object someEventKey = new object();

    // Define the SomeEvent event property.
    public event EventHandler SomeEvent
    {
        add
        {
            // Add the input delegate to the collection.
            eventDelegates.AddHandler(someEventKey, value);
        }
        remove
        {
            // Remove the input delegate from the collection.
            eventDelegates.RemoveHandler(someEventKey, value);
        }
    }

    // Raise the event with the delegate specified by someEventKey
    protected void OnSomeEvent(EventArgs e)
    {
        var handler = (EventHandler)eventDelegates[someEventKey];
        if (handler != null)
            handler(this, e);
    }
}

Deze aanpak wordt veel gebruikt in GUI-frameworks zoals WinForms, waar besturingselementen tientallen en zelfs honderden gebeurtenissen kunnen hebben.

Houd er rekening mee dat EventHandlerList niet thread-safe is, dus als u verwacht dat uw klasse door meerdere threads wordt gebruikt, moet u lock-instructies of een ander synchronisatiemechanisme toevoegen (of een opslag gebruiken die threadveiligheid biedt).



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow