Overzicht van gerouteerde gebeurtenissen (WPF .NET)
Ontwikkelaars van WPF-toepassingen (Windows Presentation Foundation) en auteurs van onderdelen kunnen gerouteerde gebeurtenissen gebruiken om gebeurtenissen door te geven via een elementstructuur en gebeurtenis-handlers aanroepen op meerdere listeners in de structuur. Deze functies zijn niet gevonden in CLR-gebeurtenissen (Common Language Runtime). Verschillende WPF-gebeurtenissen zijn gerouteerde gebeurtenissen, zoals ButtonBase.Click. In dit artikel worden basisconcepten van gerouteerde gebeurtenissen besproken en worden richtlijnen gegeven over wanneer en hoe u kunt reageren op gerouteerde gebeurtenissen.
Voorwaarden
In dit artikel wordt ervan uitgegaan dat u basiskennis hebt van de Common Language Runtime (CLR), objectgeoriënteerde programmering en hoe indeling van WPF-elementen kan worden conceptueel gezien als een structuur. Als u de voorbeelden in dit artikel wilt volgen, helpt dit als u bekend bent met Extensible Application Markup Language (XAML) en weet hoe u WPF-toepassingenschrijft.
Wat is een gerouteerde gebeurtenis?
U kunt gerouteerde gebeurtenissen overwegen vanuit het oogpunt van functionaliteit of implementatie:
Vanuit een functioneel perspectief is een gerouteerde gebeurtenis een type gebeurtenis dat handlers kan aanroepen op meerdere listeners in een elementstructuur, niet alleen op de gebeurtenisbron. Een eventlistener is het element waaraan een gebeurtenishandler is gekoppeld en aangeroepen. Een gebeurtenisbron is het element of object dat oorspronkelijk een gebeurtenis heeft gegenereerd.
Vanuit een implementatie perspectief, is een gerouteerde gebeurtenis een gebeurtenis die is geregistreerd bij het WPF-gebeurtenissysteem, ondersteund door een exemplaar van de RoutedEvent-klasse en verwerkt door het WPF-gebeurtenissysteem. Normaal gesproken wordt een gerouteerde gebeurtenis geïmplementeerd met een CLR-gebeurtenis 'wrapper' om het koppelen van handlers in XAML en in code-behind mogelijk te maken, zoals je zou doen bij een CLR-gebeurtenis.
WPF-toepassingen bevatten doorgaans veel elementen, die zijn gedeclareerd in XAML of geïnstantieerd in code. De elementen van een toepassing bestaan in de elementstructuur. Afhankelijk van hoe een gerouteerde gebeurtenis wordt gedefinieerd, wanneer de gebeurtenis wordt gegenereerd op een bronelement:
- Borrelt omhoog door de elementenboom van het bronelement naar het hoofdelement, wat meestal een pagina of venster is.
- Tunnels omlaag door de elementstructuur van het hoofdelement naar het bronelement.
- Gaat niet door de elementstructuur en vindt alleen plaats op het bronelement.
Houd rekening met de volgende gedeeltelijke elementstructuur:
<Border Height="30" Width="200" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightBlue" Orientation="Horizontal" Button.Click="YesNoCancelButton_Click">
<Button Name="YesButton">Yes</Button>
<Button Name="NoButton">No</Button>
<Button Name="CancelButton">Cancel</Button>
</StackPanel>
</Border>
De elementstructuur wordt als volgt weergegeven:
Elk van de drie knoppen is een mogelijke Click gebeurtenisbron. Wanneer op een van de knoppen wordt geklikt, wordt het Click
-evenement doorgegeven van de knop naar het hoofdelement. Aan de Button- en Border-elementen zijn geen gebeurtenis-handlers gekoppeld, maar de StackPanel wel. Mogelijk zijn er ook Click
-gebeurtenishandlers verbonden met andere elementen hoger in de structuur die niet worden weergegeven. Wanneer de Click
gebeurtenis het StackPanel
-element bereikt, roept het WPF-gebeurtenissysteem de YesNoCancelButton_Click
handler aan die eraan is gekoppeld. De gebeurtenisroute voor de Click
gebeurtenis in het voorbeeld is: Button
->StackPanel
->Border
-> opeenvolgende bovenliggende elementen.
Notitie
Het element dat oorspronkelijk een gerouteerde gebeurtenis heeft gegenereerd, wordt geïdentificeerd als de RoutedEventArgs.Source in de parameters van de gebeurtenis-handler. De gebeurtenislistener is het element waarin de gebeurtenis-handler is gekoppeld en aangeroepen en wordt geïdentificeerd als de afzender in de parameters van de gebeurtenis-handler.
Scenarios op het hoogste niveau voor gerouteerde gebeurtenissen
Hier volgen enkele scenario's die het concept van gerouteerde gebeurtenissen motiveren en onderscheiden van een typische CLR-gebeurtenis:
Samenstelling en inkapseling van besturingselementen: Verschillende besturingselementen in WPF hebben een uitgebreid inhoudsmodel. U kunt bijvoorbeeld een afbeelding in een Buttonplaatsen, waardoor de visuele structuur van de knop effectief wordt uitgebreid. Maar de toegevoegde afbeelding mag het hit-testgedrag van de knop niet verstoren. Het moet reageren wanneer een gebruiker op de afbeeldingspixels klikt.
Enkelvoudige koppelingspunten voor handlers: U kunt een handler registreren voor de
Click
gebeurtenis van elke knop, maar met gerouteerde gebeurtenissen kunt u één handler koppelen, zoals geïllustreerd in het vorige XAML-voorbeeld. Hiermee kunt u de elementstructuur onder de enkelvoudige handler wijzigen, zoals het toevoegen of verwijderen van meer knoppen, zonder dat u deClick
gebeurtenis van elke knop hoeft te registreren. Wanneer deClick
gebeurtenis wordt gegenereerd, kan de handlerlogica bepalen waar de gebeurtenis vandaan komt. De volgende handler, die is opgegeven in de eerder getoonde XAML-elementstructuur, bevat die logica:private void YesNoCancelButton_Click(object sender, RoutedEventArgs e) { FrameworkElement sourceFrameworkElement = e.Source as FrameworkElement; switch (sourceFrameworkElement.Name) { case "YesButton": // YesButton logic. break; case "NoButton": // NoButton logic. break; case "CancelButton": // CancelButton logic. break; } e.Handled = true; }
Private Sub YesNoCancelButton_Click(sender As Object, e As RoutedEventArgs) Dim frameworkElementSource As FrameworkElement = TryCast(e.Source, FrameworkElement) Select Case frameworkElementSource.Name Case "YesButton" ' YesButton logic. Case "NoButton" ' NoButton logic. Case "CancelButton" ' CancelButton logic. End Select e.Handled = True End Sub
Klasseverwerking: Gerouteerde gebeurtenissen ondersteunen een klasse-evenementenhandler die u in een class definieert. Klassehandlers verwerken een gebeurtenis vóór instantiehandlers voor dezelfde gebeurtenis op elke instantie van de klasse.
Verwijst naar een gebeurtenis zonder weerspiegeling: elke gerouteerde gebeurtenis maakt een RoutedEvent veld-id om een robuuste techniek voor gebeurtenisidentificatie te bieden waarvoor geen statische of runtime-reflectie nodig is om de gebeurtenis te identificeren.
Hoe gerouteerde gebeurtenissen worden geïmplementeerd
Een gerouteerde gebeurtenis is een gebeurtenis die is geregistreerd in het WPF-gebeurtenissysteem, ondersteund door een exemplaar van de RoutedEvent-klasse, en door ditzelfde systeem verwerkt. Het RoutedEvent
exemplaar, verkregen uit registratie, wordt doorgaans opgeslagen als public static readonly
lid van de klasse die het heeft geregistreerd. Deze klasse wordt de klasse 'eigenaar' genoemd. Normaal gesproken implementeert een gerouteerde gebeurtenis een CLR-gebeurtenis-wrapper met dezelfde naam. De CLR-gebeurteniswikkelaar bevat add
en remove
accessors om het koppelen van handlers in XAML en code-behind via taalspecifieke gebeurtenissyntaxis mogelijk te maken. De add
- en remove
-accessors overschrijven hun CLR-implementatie en roepen de methoden van de gerouteerde gebeurtenis AddHandler en RemoveHandler aan. Het gerouteerde gebeurtenisbacking- en verbindingsmechanisme is conceptueel vergelijkbaar met de manier waarop een afhankelijkheidseigenschap een CLR-eigenschap is die wordt ondersteund door de DependencyProperty-klasse en is geregistreerd bij het WPF-eigenschappensysteem.
In het volgende voorbeeld wordt de Tap
-gerouteerde gebeurtenis geregistreerd, wordt het geretourneerde RoutedEvent
-exemplaar opgeslagen en wordt een CLR-gebeurtenis-wrapper geïmplementeerd.
// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
name: "Tap",
routingStrategy: RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(CustomButton));
// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}
' Register a custom routed event using the Bubble routing strategy.
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
name:="Tap",
routingStrategy:=RoutingStrategy.Bubble,
handlerType:=GetType(RoutedEventHandler),
ownerType:=GetType(CustomButton))
' Provide CLR accessors for adding and removing an event handler.
Public Custom Event Tap As RoutedEventHandler
AddHandler(value As RoutedEventHandler)
[AddHandler](TapEvent, value)
End AddHandler
RemoveHandler(value As RoutedEventHandler)
[RemoveHandler](TapEvent, value)
End RemoveHandler
RaiseEvent(sender As Object, e As RoutedEventArgs)
[RaiseEvent](e)
End RaiseEvent
End Event
Routeringsstrategieën
Gerouteerde gebeurtenissen maken gebruik van een van de drie routeringsstrategieën:
Bubbling: In eerste instantie worden gebeurtenishandlers op de gebeurtenisbron aangeroepen. De gerouteerde gebeurtenis routeert vervolgens naar opeenvolgende ouderlijke elementen, waarbij hun gebeurtenishandlers in volgorde worden aangeroepen totdat deze de wortel van de elementstructuur bereikt. De meeste gerouteerde gebeurtenissen maken gebruik van de bubbelrouteringsstrategie. Gerouteerde gebeurtenissen worden over het algemeen gebruikt om wijzigingen in invoer of toestand van samengestelde besturingselementen of andere elementen van de gebruikersinterface door te geven.
Tunneling-: Aanvankelijk worden de gebeurtenishandlers bij de wortel van de elementboom aangeroepen. De gerouteerde gebeurtenis wordt vervolgens gerouteerd naar opeenvolgende onderliggende elementen, waarbij de gebeurtenis-handlers op zijn beurt worden aangeroepen totdat de gebeurtenisbron wordt bereikt. Gebeurtenissen die een tunnelroute volgen, worden ook wel preview- gebeurtenissen genoemd. WPF-invoergebeurtenissen worden over het algemeen geïmplementeerd als een preview- en bubblingparen.
Direct: alleen gebeurtenis-handlers op de gebeurtenisbron worden aangeroepen. Deze strategie voor niet-routering is vergelijkbaar met windows Forms UI-frameworkgebeurtenissen, die standaard CLR-gebeurtenissen zijn. In tegenstelling tot CLR-gebeurtenissen ondersteunen directe gerouteerde gebeurtenissen klasseafhandeling en kunnen worden gebruikt door EventSetters en EventTriggers.
Waarom gerouteerde gebeurtenissen gebruiken?
Als applicatieontwikkelaar hoeft u niet altijd te weten of u zich zorgen hoeft te maken dat de gebeurtenis die u verwerkt, wordt geïmplementeerd als een gerouteerde gebeurtenis. Gerouteerde gebeurtenissen hebben speciaal gedrag, maar dat gedrag is grotendeels onzichtbaar als u een gebeurtenis verwerkt op het element dat het heeft gegenereerd. Gerouteerde gebeurtenissen zijn echter relevant wanneer u een event-handler wilt koppelen aan een bovenliggend element om gebeurtenissen te verwerken die zijn gegenereerd door onderliggende elementen, zoals binnen een samengesteld controle-element.
Gerouteerde gebeurtenislisteners hebben de gerouteerde gebeurtenissen die ze verwerken niet nodig om lid te zijn van hun klas. Elke UIElement of ContentElement kan een gebeurtenislistener zijn voor elke gerouteerde gebeurtenis. Aangezien visuele elementen zijn afgeleid van UIElement
of ContentElement
, kunt u gerouteerde gebeurtenissen gebruiken als conceptuele interface die ondersteuning biedt voor de uitwisseling van gebeurtenisgegevens tussen verschillende elementen in een toepassing. Het concept van een "interface" voor gerouteerde evenementen is met name van toepassing op invoerevenementen.
Gerouteerde gebeurtenissen ondersteunen de uitwisseling van gebeurtenisgegevens tussen elementen langs de gebeurtenisroute, omdat elke listener toegang heeft tot hetzelfde exemplaar van gebeurtenisgegevens. Als één element iets in de gebeurtenisgegevens wijzigt, is die wijziging zichtbaar voor volgende elementen in de gebeurtenisroute.
Naast het routeringsaspect kunt u ervoor kiezen om een gerouteerde gebeurtenis te implementeren in plaats van een standaard CLR-gebeurtenis om deze redenen:
Voor sommige WPF-stijl- en temperingsfuncties, zoals EventSetters en EventTriggers, moet de gebeurtenis waarnaar wordt verwezen een gerouteerde gebeurtenis zijn.
Routeringsgebeurtenissen ondersteunen klasse-handlers die een gebeurtenis verwerken voordat elke instantie-handler voor dezelfde gebeurtenis op alle exemplaren van de luisteraarklasse wordt uitgevoerd. Deze functie is handig in het ontwerp van besturingselementen omdat uw klassehandler gebeurtenisgestuurd klassegedrag kan afdwingen dat niet per ongeluk kan worden onderdrukt door een instancehandler.
Een gerouteerde gebeurtenis-handler koppelen en implementeren
In XAML koppelt u een gebeurtenis-handler aan een element door de naam van de gebeurtenis als een kenmerk in het gebeurtenislistenerelement te declareren. De kenmerkwaarde is de naam van de handlermethode. De handlermethode moet worden geïmplementeerd in de code-behind gedeeltelijke klasse voor de XAML-pagina. De event listener is het element waarop de event handler is gekoppeld en aangeroepen.
Voor een gebeurtenis die lid is (overgenomen of anderszins) van de listenerklasse, kunt u als volgt een handler koppelen:
<Button Name="Button1" Click="Button_Click">Click me</Button>
Als de gebeurtenis geen lid is van de klasse van de listener, moet u de naam van de gekwalificeerde gebeurtenis gebruiken in de vorm van <owner type>.<event name>
. Omdat de klasse StackPanel de gebeurtenis Click niet implementeert, moet u bijvoorbeeld de syntaxis van de gekwalificeerde gebeurtenisnaam gebruiken om een handler toe te voegen aan een StackPanel
voor een Click
-gebeurtenis die naar dat element opborrelt:
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
De handtekening van de gebeurtenis-handlermethode in code-behind moet overeenkomen met het gemachtigde type voor de gerouteerde gebeurtenis. De sender
-parameter van de RoutedEventHandler delegate voor het Click-event specificeert het element waaraan de event handler is gekoppeld. De parameter args
van de RoutedEventHandler
gedelegeerde bevat de gebeurtenisgegevens. Een geschikte code-behind-implementatie voor de Button_Click
event handler kan zijn:
private void Button_Click(object sender, RoutedEventArgs e)
{
// Click event logic.
}
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
' Click event logic.
End Sub
Hoewel RoutedEventHandler de basisgerouteerde gebeurtenishandler is, vereisen sommige besturingselementen of implementatiescenario's verschillende gemachtigden die meer gespecialiseerde gebeurtenisgegevens ondersteunen. Voor de DragEnter-gerouteerde gebeurtenis moet uw handler bijvoorbeeld de DragEventHandler-delegate implementeren. Hierdoor heeft uw handlercode toegang tot de eigenschap DragEventArgs.Data in gebeurtenisgegevens, die de nettolading van het klembord uit de sleepbewerking bevat.
De XAML-syntaxis voor het toevoegen van gerouteerde gebeurtenis-handlers is hetzelfde als voor standaard CLR-gebeurtenis-handlers. Zie XAML in WPFvoor meer informatie over het toevoegen van gebeurtenis-handlers in XAML. Zie Een gerouteerde gebeurtenisverwerken voor een volledig voorbeeld van het koppelen van een gebeurtenishandler aan een element met XAML.
Als u een gebeurtenis-handler voor een gerouteerde gebeurtenis wilt koppelen aan een element met behulp van code, hebt u over het algemeen twee opties:
Roep de methode AddHandler rechtstreeks aan. Gerouteerde gebeurtenis-handlers kunnen altijd op deze manier worden gekoppeld. In dit voorbeeld wordt een
Click
event handler gekoppeld aan een knop via de methodeAddHandler
:Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
Als u een handler voor de
Click
gebeurtenis van de knop wilt koppelen aan een ander element in de route van de gebeurtenis, zoals een StackPanel met de naamStackPanel1
:StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
Als de gerouteerde gebeurtenis een CLR-gebeurteniswikkelaar implementeert, gebruikt u taalspecifieke gebeurtenissyntaxis om eventhandlers toe te voegen, net zoals voor een standaard CLR-gebeurtenis. De meeste bestaande WPF-gerouteerde gebeurtenissen implementeren de CLR-wrapper, waardoor taalspecifieke gebeurtenissyntaxis wordt ingeschakeld. In dit voorbeeld wordt een
Click
gebeurtenis-handler gekoppeld aan een knop met behulp van taalspecifieke syntaxis:Button1.Click += Button_Click;
AddHandler Button1.Click, AddressOf Button_Click
Zie Een gebeurtenis-handler toevoegen met behulp van codevoor een voorbeeld van het toevoegen van een gebeurtenis-handler in code. Als u codeert in Visual Basic, kunt u ook het trefwoord Handles
gebruiken om handlers toe te voegen als onderdeel van de handlerdeclaraties. Zie Visual Basic- en WPF-gebeurtenisafhandelingvoor meer informatie.
Het concept van afgehandeld
Alle gerouteerde gebeurtenissen delen een gemeenschappelijke basisklasse voor gebeurtenisgegevens. Dit is de RoutedEventArgs-klasse. De klasse RoutedEventArgs
definieert de booleaanse eigenschap Handled. Het doel van de eigenschap Handled
is zodat elke gebeurtenis-handler langs de route van de gebeurtenis de gebeurtenis als afgehandeldmarkeert. Als u een gebeurtenis wilt markeren als verwerkt, stelt u de waarde van Handled
in op true
in de gebeurtenis-handlercode.
De waarde van Handled
beïnvloedt hoe een gerouteerde gebeurtenis wordt verwerkt terwijl deze langs de gebeurtenisroute loopt. Als Handled
gelijk is aan true
in de gedeelde gegevens van een gerouteerde gebeurtenis, worden handlers die verbonden zijn aan andere elementen verder langs de gebeurtenisroute doorgaans niet aangeroepen voor dat specifieke gebeurtenisexemplaar. Bij de meest voorkomende handlerscenario's stopt het markeren van een gebeurtenis als verwerkt effectief de volgende handlers langs de gebeurtenisroute, hetzij instantie- of klassehandlers, van reageren op die specifieke gebeurtenisinstantie. In zeldzame gevallen waarin het nodig is dat uw event handler reageert op gerouteerde gebeurtenissen die als afgehandeld zijn gemarkeerd, kunt u het volgende uitvoeren:
Koppel de handler in code-behind met behulp van de AddHandler(RoutedEvent, Delegate, Boolean) overbelasting, waarbij de parameter
handledEventsToo
is ingesteld optrue
.Stel het kenmerk HandledEventsToo in een
EventSetter
in optrue
.
Het concept van Handled
kan van invloed zijn op de manier waarop u uw toepassing ontwerpt en uw gebeurtenis-handlers codet. U kunt Handled
beschouwen als een eenvoudig protocol voor de verwerking van gerouteerde gebeurtenissen. Hoe u dit protocol gebruikt, is aan u, maar het verwachte gebruik van de parameter Handled
is:
Als een gerouteerde gebeurtenis is gemarkeerd als afgehandeld, hoeft deze niet opnieuw te worden afgehandeld door andere elementen langs de route.
Als een gerouteerde gebeurtenis niet als afgehandeld is gemarkeerd, dan hebben listeners die eerder in de gebeurtenisroute zitten geen handler voor de gebeurtenis, of hebben geen van de geregistreerde handlers op de gebeurtenis gereageerd op een manier die het rechtvaardigt de gebeurtenis als afgehandeld te markeren. Handlers op de huidige listener hebben drie mogelijke acties:
Doe helemaal geen actie. De gebeurtenis blijft onverwerkt en routeert naar de volgende listener in de structuur.
Voer code uit als reactie op de gebeurtenis, maar niet in die mate dat de gebeurtenis als afgehandeld wordt gemarkeerd. De gebeurtenis blijft onverwerkt en wordt doorgestuurd naar de volgende luisteraar in de structuur.
Voer code uit als reactie op de gebeurtenis, voor zover dat het rechtvaardigt om de gebeurtenis als afgehandeld te beschouwen. Markeer de gebeurtenis zoals verwerkt in de gebeurtenisgegevens. De gebeurtenis routeert nog steeds naar de volgende listener in de structuur, maar de meeste listeners roepen geen verdere handlers aan. De uitzondering is listeners met handlers die specifiek zijn geregistreerd bij
handledEventsToo
ingesteld optrue
.
Voor meer informatie over het verwerken van gerouteerde gebeurtenissen, zie Markeren van gerouteerde gebeurtenissen als afgehandeld, en klassenafhandeling.
Hoewel ontwikkelaars die alleen een bubbelende gerouteerde gebeurtenis verwerken op het object dat het heeft gegenereerd, zich mogelijk geen zorgen maken over andere luisteraars, is het raadzaam om de gebeurtenis toch als afgehandeld te markeren. Dit voorkomt onverwachte bijwerkingen als een element verder langs de gebeurtenisroute een handler heeft voor dezelfde gerouteerde gebeurtenis.
Klassehandlers
Gerouteerde gebeurtenis-handlers kunnen instantie handlers of klasse handlers zijn. Klassehandlers voor een bepaalde class worden aangeroepen voordat een instantiehandler reageert op dezelfde gebeurtenis op een exemplaar van die class. Vanwege dit gedrag worden gerouteerde evenementen, wanneer ze als verwerkt worden gemarkeerd, vaak binnen klassenhandlers gemarkeerd als zodanig. Er zijn twee typen klasse-handlers:
- statische klassegebeurtenishandlers, die zijn geregistreerd door de RegisterClassHandler methode aan te roepen binnen een statische klasse-constructeur.
- Overschrijf klassegebeurtenishandlers, die zijn geregistreerd door virtuele gebeurtenismethoden van de basisklasse te overschrijven. Basisklasse-methoden voor virtuele gebeurtenissen bestaan voornamelijk voor invoergebeurtenissen en hebben namen die beginnen met Naam van<gebeurtenis> en OnPreview<gebeurtenisnaam>.
Sommige WPF-besturingselementen hebben inherente klasseafhandeling voor bepaalde gerouteerde gebeurtenissen. Klasseafhandeling kan het uiterlijk geven dat de gerouteerde gebeurtenis nooit wordt gegenereerd, maar in werkelijkheid wordt deze gemarkeerd als afgehandeld door een klasse-handler. Als u uw eventhandler nodig heeft om te reageren op de afgehandelde gebeurtenis, kunt u uw handler registreren met handledEventsToo
ingesteld op true
. Zie Gerouteerde gebeurtenissen markeren als verwerkt en klasseverwerkingvoor meer informatie over het implementeren van uw eigen klassenhandlers of het omzeilen van ongewenste klasseverwerking.
Gekoppelde gebeurtenissen in WPF
De XAML-taal definieert ook een speciaal type gebeurtenis dat een gekoppelde gebeurteniswordt genoemd. Gekoppelde gebeurtenissen kunnen worden gebruikt om een nieuwe gerouteerde gebeurtenis te definiëren in een niet-element klasse en die gebeurtenis op te roepen 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, verspreiden ze zich door de elementstructuur wanneer ze op een element worden opgeroepen.
In de syntaxis van XAML wordt een gekoppelde gebeurtenis opgegeven met de naam van de gebeurtenis en eigenaartype, in de vorm van <owner type>.<event name>
. Omdat de naam van het evenement is gekwalificeerd door de naam van het type eigenaar, kan de gebeurtenis worden gekoppeld 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. U kunt ook handlers toevoegen voor gekoppelde gebeurtenissen in de code-achterkant door de AddHandler-methode aan te roepen voor het object waaraan de handler moet worden toegevoegd.
Het WPF-invoersysteem maakt uitgebreid gebruik van gekoppelde gebeurtenissen. Bijna al deze gekoppelde gebeurtenissen worden echter weergegeven als gelijkwaardige niet-gekoppelde gerouteerde gebeurtenissen via basiselementen. 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 door gebruik te maken van de gekoppelde gebeurtenissyntaxis in XAML of in de code-achtergrond.
Zie Overzicht van gekoppelde gebeurtenissenvoor meer informatie over gekoppelde gebeurtenissen in WPF.
Gekwalificeerde gebeurtenisnamen in XAML
De <owner type>.<event name>
-syntaxis kwalificeert een gebeurtenisnaam met de naam van zijn eigenaartype. Met deze syntaxis kan een gebeurtenis worden gekoppeld aan een element, niet alleen elementen die de gebeurtenis implementeren als lid van hun klasse. De syntaxis is van toepassing bij het koppelen van handlers in XAML voor gekoppelde gebeurtenissen of gerouteerde gebeurtenissen op willekeurige elementen langs de gebeurtenisroute. Overweeg het scenario waarin u een handler aan een bovenliggend element wilt koppelen om gerouteerde gebeurtenissen te verwerken die zijn gegenereerd op onderliggende elementen. Als het bovenliggende element de gerouteerde gebeurtenis niet als lid heeft, moet u de syntaxis van de gekwalificeerde gebeurtenisnaam gebruiken. Bijvoorbeeld:
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
In het voorbeeld is de listener van het bovenliggende element waaraan de gebeurtenis-handler wordt toegevoegd een StackPanel. De Click gerouteerde gebeurtenis wordt echter geïmplementeerd en gegenereerd op de ButtonBase-klasse, en is beschikbaar voor de Button-klasse via overerving. Hoewel de Button-klasse eigenaar is van de Click
-gebeurtenis, staat het systeem voor gerouteerde gebeurtenissen toe dat handlers voor elke gerouteerde gebeurtenis worden gekoppeld aan een UIElement- of ContentElement-instantie met een listener die anders handlers voor een CLR-gebeurtenis zou kunnen hebben. De standaardnaamruimte xmlns
voor deze namen van gekwalificeerde gebeurteniskenmerken is doorgaans de standaard WPF-xmlns
-naamruimte, maar u kunt ook voorvoegselnaamruimten opgeven voor aangepaste gerouteerde gebeurtenissen. Zie XAML-naamruimten en naamruimtetoewijzing voor WPF XAML-voor meer informatie over xmlns
.
WPF-invoerevenementen
Een veelgebruikte toepassing van gerouteerde gebeurtenissen binnen het WPF-platform is voor invoergebeurtenissen. Volgens de conventie hebben WPF gerouteerde gebeurtenissen die een tunnelingroute volgen een naam die wordt voorafgegaan door 'Preview'. Het voorvoegsel Preview geeft aan dat de preview-gebeurtenis is voltooid voordat de gekoppelde bubblinggebeurtenis wordt gestart. Invoergebeurtenissen komen vaak in paren voor, waarbij de ene een preview-gebeurtenis is en de andere een "bubbelende" gerouteerde gebeurtenis. Bijvoorbeeld PreviewKeyDown en KeyDown. De gebeurtenisparen delen hetzelfde exemplaar van gebeurtenisgegevens, die voor PreviewKeyDown
en KeyDown
van het type KeyEventArgsis. Soms hebben invoergebeurtenissen alleen een bubblingversie of alleen een directe gerouteerde versie. In de API-documentatie wordt er naar gerouteerde gebeurtenisonderwerpen verwezen, waarbij gerouteerde gebeurtenisparen aan de orde komen en de routeringsstrategie voor elke gerouteerde gebeurtenis wordt verduidelijkt.
WPF-invoergebeurtenissen die in paren worden geleverd, worden geïmplementeerd, zodat één gebruikersactie van een invoerapparaat, zoals een muisknop, de preview- en bubblinggebeurtenissen op volgorde verhoogt. Eerst wordt de preview-gebeurtenis gegenereerd en wordt de route voltooid. Na voltooiing van de preview-gebeurtenis wordt de bubbling-gebeurtenis opgeroepen en voltooit het zijn route. De RaiseEvent methode-aanroep in de implementatieklasse waarmee de gebeurtenis wordt gegenereerd, hergebruikt de gebeurtenisgegevens van de preview-gebeurtenis voor de bubbling-gebeurtenis.
Een preview-invoergebeurtenis die is gemarkeerd als verwerkt, zal geen normaal geregistreerde gebeurtenis-handlers aanroepen voor de rest van het previewtraject en de gekoppelde bubbling-gebeurtenis wordt niet gegenereerd. Dit afhandelingsgedrag is handig voor ontwerpers van samengestelde besturingselementen die op hittest gebaseerde invoergebeurtenissen of op focus gebaseerde invoergebeurtenissen op het hoogste niveau van hun controle willen melden. Elementen op het hoogste niveau van het besturingselement hebben de mogelijkheid om preview-gebeurtenissen van subonderdelen te verwerken en te vervangen door een gebeurtenis die specifiek is voor het hoogste niveau van het besturingselement.
Bekijk het volgende voorbeeld van een invoer gebeurtenis om te illustreren hoe de verwerking van invoerevenementen werkt. In de volgende boomillustratie is leaf element #2
de bron van zowel de PreviewMouseDown
als de MouseDown
gekoppelde evenementen.
De volgorde van gebeurtenisverwerking na een muis-omlaagactie op leaf-element 2 is:
-
PreviewMouseDown
tunneling-gebeurtenis op het hoofdelement. -
PreviewMouseDown
tunnelinggebeurtenis op tussenliggend element #1. -
PreviewMouseDown
tunneling-gebeurtenis op leaf-element 2, het bronelement. -
MouseDown
bubbling-gebeurtenis op blad-element #2, dat het bronelement is. -
MouseDown
bubbling-gebeurtenis op tussenliggend element #1. -
MouseDown
bubbelende gebeurtenis op het hoofdelement.
De afgehandelde gebeurtenisdeleger biedt verwijzingen naar zowel het object dat de gebeurtenis heeft doen optreden als het object waarin de handler is aangeroepen. Het object dat de gebeurtenis oorspronkelijk heeft gegenereerd, wordt gerapporteerd door de eigenschap Source in de gebeurtenisgegevens. Het object waarop de handler is aangeroepen, wordt gerapporteerd door de afzender parameter. Voor een bepaald gerouteerd gebeurtenisvoorbeeld verandert het object dat de gebeurtenis veroorzaakte niet naarmate de gebeurtenis door de elementstructuur loopt, maar de sender
wel. In stap 3 en 4 van het voorgaande diagram zijn de Source
en sender
hetzelfde object.
Als uw invoergebeurtenishandler de toepassingsspecifieke logica voltooit die nodig is om op het evenement te reageren, moet u de invoergebeurtenis als afgehandeld markeren. Wanneer een invoergebeurtenis is gemarkeerd als Handled, worden handlers verder langs de gebeurtenisroute niet aangeroepen. Invoergebeurtenis-handlers worden echter aangeroepen als ze zijn geregistreerd waarbij de handledEventsToo
parameter is ingesteld op true
, zelfs wanneer een gebeurtenis als verwerkt is gemarkeerd. Voor meer informatie, zie Preview-gebeurtenissen en Gerouteerde gebeurtenissen markeren als verwerkt en klasseafhandeling.
Het concept van preview- en bubblinggebeurtenisparen, met gedeelde gebeurtenisgegevens en opeenvolgende verhoging van de preview-gebeurtenis, vervolgens de bubblinggebeurtenis, is alleen van toepassing op sommige WPF-invoergebeurtenissen en niet op alle gerouteerde gebeurtenissen. Als u uw eigen invoerevenement implementeert om een geavanceerd scenario aan te pakken, overweeg dan de WPF-invoereventpaarbenadering te volgen.
Als u uw eigen samengestelde besturingselement implementeert dat reageert op invoergebeurtenissen, kunt u overwegen preview-gebeurtenissen te gebruiken om invoergebeurtenissen die zijn gegenereerd op subonderdelen te onderdrukken en te vervangen door een gebeurtenis op het hoogste niveau die het volledige besturingselement vertegenwoordigt. Zie Gerouteerde gebeurtenissen markeren als verwerkt en klasseafhandelingvoor meer informatie.
Zie voor meer informatie over het WPF-invoersysteem en hoe invoer en gebeurtenissen communiceren in typische toepassingsscenario's Overzicht van invoer.
EventSetters en EventTriggers
In opmaakstijlen kunt u vooraf gedeclareerde XAML-gebeurtenisverwerkingssyntaxis opnemen met behulp van een EventSetter. Wanneer de XAML wordt verwerkt, wordt de handler waarnaar wordt verwezen toegevoegd aan de gestijlde instantie. U kunt alleen een EventSetter
declareren voor een gerouteerde gebeurtenis. In het volgende voorbeeld wordt de ApplyButtonStyle
gebeurtenis-handlermethode waarnaar wordt verwezen, geïmplementeerd in code-behind.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="ApplyButtonStyle"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Click="Button_Click">Click me</Button>
</StackPanel>
Het is waarschijnlijk dat het Style
knooppunt al andere stijlgegevens bevat die betrekking hebben op besturingselementen van het opgegeven type, en dat het opnemen van EventSetter in deze stijlen het hergebruik van code bevordert, zelfs op markuptaalniveau. Daarnaast abstraheert een EventSetter
methodenamen voor handlers van de algemene toepassingen en pagina-opmaak.
Een andere gespecialiseerde syntaxis die de gerouteerde gebeurtenis- en animatiefuncties van WPF combineert, is een EventTrigger. Net als bij de EventSetter
kunt u alleen een EventTrigger
declareren voor een gerouteerd event. Normaal gesproken wordt een EventTrigger
gedeclareerd als onderdeel van een stijl, maar een EventTrigger
kan worden gedeclareerd op elementen op paginaniveau als onderdeel van de Triggers verzameling of in een ControlTemplate. Met een EventTrigger
kunt u een Storyboard opgeven die wordt uitgevoerd wanneer een gerouteerde gebeurtenis een element in de route bereikt dat een EventTrigger
voor die gebeurtenis declareert. Het voordeel van een EventTrigger
over het afhandelen van de gebeurtenis en het starten van een bestaand storyboard is dat een EventTrigger
een betere controle biedt over het storyboard en het runtime-gedrag. Zie Gebeurtenistriggers gebruiken om een storyboard te beheren nadat deze is gestartvoor meer informatie.
Meer informatie over gerouteerde gebeurtenissen
U kunt de concepten en richtlijnen in dit artikel gebruiken als uitgangspunt bij het maken van aangepaste gerouteerde gebeurtenissen in uw eigen klassen. U kunt uw aangepaste gebeurtenissen ook ondersteunen met gespecialiseerde gebeurtenisgegevensklassen en gemachtigden. Een eigenaar van een gerouteerde gebeurtenis kan elke klasse zijn, maar gerouteerde gebeurtenissen moeten worden gegenereerd en verwerkt door UIElement of ContentElement afgeleide klassen om nuttig te zijn. Voor meer informatie over aangepaste gebeurtenissen, zie Een aangepaste gerouteerde gebeurtenis maken.
Zie ook
.NET Desktop feedback