Delen via


Overzicht van gekoppelde gebeurtenissen (WPF .NET)

Extensible Application Markup Language (XAML) definieert een taalonderdeel en gebeurtenistype dat een gekoppelde gebeurteniswordt genoemd. Gekoppelde gebeurtenissen kunnen worden gebruikt om een nieuwe gerouteerde gebeurtenis te definiëren in een niet-element-klasse en deze gebeurtenis op te wekken op elk element in uw boomstructuur. Hiervoor moet u de gekoppelde gebeurtenis registreren als een gerouteerde gebeurtenis en specifieke back-upcode opgeven die ondersteuning biedt voor gekoppelde gebeurtenisfunctionaliteit. Aangezien gekoppelde gebeurtenissen zijn geregistreerd als gerouteerde gebeurtenissen, propageren ze door de elementstructuur wanneer ze op een element worden opgeroepen.

Voorwaarden

In het artikel wordt ervan uitgegaan dat u basiskennis hebt van de door Windows Presentation Foundation (WPF) gerouteerde gebeurtenissen (routed events) en dat u Overzicht van gerouteerde gebeurtenissen (Routed events overview) en XAML in WPFhebt gelezen. Als u de voorbeelden in dit artikel wilt volgen, helpt dit als u bekend bent met XAML en weet hoe u WPF-toepassingen schrijft.

Syntaxis van gekoppelde gebeurtenis

In de syntaxis van XAML wordt een gekoppelde gebeurtenis opgegeven met de naam van de gebeurtenis en het type eigenaar, in de vorm van <owner type>.<event name>. Omdat de gebeurtenisnaam is gekwalificeerd met de naam van het type eigenaar, kan de syntaxis de gebeurtenis koppelen aan elk element dat kan worden geïnstantieerd. Deze syntaxis is ook van toepassing op handlers voor reguliere gerouteerde gebeurtenissen die zijn gekoppeld aan een willekeurig element langs de gebeurtenisroute.

De volgende syntaxis van het XAML-kenmerk koppelt de AquariumFilter_Clean handler voor de AquariumFilter.Clean gekoppelde gebeurtenis aan het aquarium1-element:

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

In dit voorbeeld is het aqua: voorvoegsel nodig omdat de AquariumFilter- en Aquarium klassen bestaan in een andere CLR-naamruimte (Common Language Runtime) en assembly.

U kunt ook handlers koppelen voor gekoppelde gebeurtenissen in de achterliggende code. Hiervoor roept u de AddHandler methode aan voor het object waaraan de handler moet koppelen en de gebeurtenis-id en handler als parameters moet doorgeven aan de methode.

Hoe WPF gekoppelde gebeurtenissen implementeert

Aan WPF gekoppelde gebeurtenissen worden geïmplementeerd als gerouteerde gebeurtenissen die worden ondersteund door een RoutedEvent veld. Als gevolg hiervan worden gekoppelde gebeurtenissen doorgegeven via de elementstructuur nadat ze zijn gegenereerd. Over het algemeen is het object dat de gekoppelde gebeurtenis genereert, ook wel de gebeurtenisbron genoemd, een systeem- of servicebron. Systeem- of servicebronnen zijn geen direct onderdeel van de elementstructuur. Voor andere gekoppelde gebeurtenissen kan de gebeurtenisbron een element in de structuur zijn, zoals een onderdeel in een samengesteld besturingselement.

Gekoppelde gebeurtenisscenario's

In WPF worden gekoppelde gebeurtenissen gebruikt in bepaalde functiegebieden waar een abstractie op serviceniveau is. WPF maakt bijvoorbeeld gebruik van gekoppelde gebeurtenissen die zijn ingeschakeld door de statische Mouse of Validation klassen. Klassen die interactie hebben met of een service gebruiken, kunnen communiceren met een gebeurtenis met behulp van de syntaxis van gekoppelde gebeurtenissen of de gekoppelde gebeurtenis weergeven als een gerouteerde gebeurtenis. De laatste optie maakt deel uit van de wijze waarop een klasse de mogelijkheden van de service kan integreren.

Het WPF-invoersysteem maakt uitgebreid gebruik van gekoppelde gebeurtenissen. Bijna al deze gekoppelde gebeurtenissen worden echter via basiselementen weergegeven als gerouteerde gebeurtenissen die equivalent zijn aan niet-gekoppelde gebeurtenissen. Elke gerouteerde invoergebeurtenis is een lid van de basiselementklasse en wordt ondersteund met een 'CLR-gebeurteniswrapper'. U gebruikt of verwerkt gekoppelde gebeurtenissen zelden rechtstreeks. Het is bijvoorbeeld eenvoudiger om de onderliggende gekoppelde Mouse.MouseDown gebeurtenis op een UIElement te verwerken via de equivalente UIElement.MouseDown gerouteerde gebeurtenis dan met behulp van de gekoppelde gebeurtenissyntaxis in XAML of code-behind.

Gekoppelde gebeurtenissen dienen voor een architectuurdoel door toekomstige uitbreiding van invoerapparaten mogelijk te maken. Een nieuw invoerapparaat hoeft bijvoorbeeld alleen Mouse.MouseDown te verhogen om de invoer van de muis te simuleren en hoeft niet te worden afgeleid van Mouse om dit te doen. Dit scenario omvat codeafhandeling van de gebeurtenis, omdat XAML-verwerking van de gekoppelde gebeurtenis niet relevant zou zijn.

Een gekoppelde gebeurtenis afhandelen

Het proces voor het coderen en verwerken van een gekoppelde gebeurtenis is in feite hetzelfde als voor een niet-gekoppelde gerouteerde gebeurtenis.

Zoals eerder opgemerkt, zijn bestaande WPF-gekoppelde gebeurtenissen doorgaans niet bedoeld om rechtstreeks te worden verwerkt in WPF. Vaker is het doel van een gekoppelde gebeurtenis om een element in een samengesteld besturingselement in staat te stellen de status ervan te rapporteren aan een bovenliggend element binnen het besturingselement. In dat scenario wordt de gebeurtenis gegenereerd in code en is afhankelijk van klasseafhandeling in de relevante bovenliggende klasse. Er wordt bijvoorbeeld verwacht dat items binnen een Selector de gekoppelde gebeurtenis Selected genereren, die vervolgens wordt verwerkt door de Selector-klasse. De Selector-klasse converteert mogelijk de Selected gebeurtenis naar de SelectionChanged gerouteerde gebeurtenis. Zie voor meer informatie over gerouteerde gebeurtenissen en klasseafhandeling de sectie Gerouteerde gebeurtenissen markeren als verwerkt en klasseafhandeling.

Een aangepaste gekoppelde gebeurtenis definiëren

Als u afgeleid bent van algemene WPF-basisklassen, kunt u uw aangepaste gekoppelde gebeurtenis implementeren door twee toegangsmethoden in uw klasse op te slaan. Deze methoden zijn:

  • Een <gebeurtenisnaam toevoegen>handler methode, met een eerste parameter die het element is waarop de gebeurtenis-handler is gekoppeld en een tweede parameter die de gebeurtenis-handler is die moet worden toegevoegd. De methode moet public en staticzijn, zonder retourwaarde. De methode roept de AddHandler basisklassemethode aan, waarbij de gerouteerde gebeurtenis en handler als argumenten worden doorgegeven. Deze methode ondersteunt de syntaxis van het XAML-kenmerk voor het koppelen van een gebeurtenishandler aan een element. Met deze methode kunt u ook codetoegang tot het gebeurtenis-handlerarchief voor de gekoppelde gebeurtenis inschakelen.

  • Een <gebeurtenisnaam verwijderen>handler methode, met een eerste parameter die het element is waarop de gebeurtenis-handler is gekoppeld en een tweede parameter die de gebeurtenis-handler is die moet worden verwijderd. De methode moet public en staticzijn, zonder retourwaarde. De methode roept de RemoveHandler basisklassemethode aan, waarbij de gerouteerde gebeurtenis en handler als argumenten worden doorgegeven. Met deze methode kunt u codetoegang tot het gebeurtenishandlerarchief voor de gekoppelde gebeurtenis inschakelen.

WPF implementeert gekoppelde gebeurtenissen als gerouteerde gebeurtenissen omdat de id voor een RoutedEvent wordt gedefinieerd door het WPF-gebeurtenissysteem. Het routeren van een gebeurtenis is ook een natuurlijke uitbreiding van het concept op taalniveau van XAML van een gekoppelde gebeurtenis. Deze implementatiestrategie beperkt de verwerking van gekoppelde gebeurtenissen tot UIElement afgeleide klassen of ContentElement afgeleide klassen, omdat alleen die klassen AddHandler implementaties hebben.

De volgende code definieert bijvoorbeeld de Clean gekoppelde gebeurtenis in de klasse AquariumFilter eigenaar, die geen elementklasse is. De code definieert de gekoppelde gebeurtenis als een gerouteerde gebeurtenis en implementeert de vereiste toegangsmethoden.

public class AquariumFilter
{
    // Register a custom routed event using the bubble routing strategy.
    public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));

    // Provide an add handler accessor method for the Clean event.
    public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.AddHandler(CleanEvent, handler);
    }

    // Provide a remove handler accessor method for the Clean event.
    public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.RemoveHandler(CleanEvent, handler);
    }
}
Public Class AquariumFilter

    ' Register a custom routed event using the bubble routing strategy.
    Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))

    ' Provide an add handler accessor method for the Clean event.
    Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[AddHandler](CleanEvent, handler)
        End If
    End Sub

    ' Provide a remove handler accessor method for the Clean event.
    Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[RemoveHandler](CleanEvent, handler)
        End If
    End Sub

End Class

De RegisterRoutedEvent methode die de gekoppelde gebeurtenis-id retourneert, is dezelfde methode die wordt gebruikt voor het registreren van niet-gekoppelde gerouteerde gebeurtenissen. Zowel gekoppelde als niet-gekoppelde gerouteerde gebeurtenissen worden geregistreerd bij een gecentraliseerde interne opslag. Deze implementatie van het gebeurtenisarchief maakt het concept 'gebeurtenissen als een interface' mogelijk dat wordt besproken in Overzicht van gerouteerde gebeurtenissen.

In tegenstelling tot de CLR-gebeurtenis 'wrapper' die wordt gebruikt om niet-gekoppelde gerouteerde events te ondersteunen, kunnen de toegangsfuncties voor gekoppelde gebeurtenissen worden geïmplementeerd in klassen die niet zijn afgeleid van UIElement of ContentElement. Dit is mogelijk omdat de gekoppelde event-backupcode de methoden UIElement.AddHandler en UIElement.RemoveHandler aanroept op een doorgegeven UIElement instantie. Daarentegen roept de CLR-wrapper voor niet-gekoppelde gerouteerde gebeurtenissen deze methoden rechtstreeks aan op de klasse die eigenaar is, zodat de klasse moet worden afgeleid van UIElement.

Een gekoppelde WPF-gebeurtenis activeren

Het proces voor het aanroepen van een gekoppelde gebeurtenis is in wezen hetzelfde als voor een niet-gekoppelde routed gebeurtenis.

Normaal gesproken hoeft uw code geen bestaande door WPF gedefinieerde gekoppelde gebeurtenissen te genereren, omdat deze gebeurtenissen het algemene conceptuele model van de service volgen. In dat model zijn serviceklassen, zoals InputManager, verantwoordelijk voor het verhogen van door WPF gedefinieerde gekoppelde gebeurtenissen.

Wanneer u een aangepaste gekoppelde gebeurtenis definieert met behulp van het WPF-model waarbij gekoppelde gebeurtenissen zijn gebaseerd op gerouteerde gebeurtenissen, gebruikt u de methode UIElement.RaiseEvent om een gekoppelde gebeurtenis op te roepen op een UIElement of ContentElement. Wanneer u een gerouteerde gebeurtenis opvraagt, ongeacht of deze is gekoppeld of niet, moet u een element in de elementstructuur aanwijzen als gebeurtenisbron. Vervolgens wordt deze bron gemeld als de RaiseEvent oproeper. Als u bijvoorbeeld de gekoppelde gebeurtenis AquariumFilter.Clean wilt oproepen op aquarium1:

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

In het voorgaande voorbeeld is aquarium1 de gebeurtenisbron.

Zie ook