Overzicht van gerouteerde gebeurtenissen
In dit onderwerp wordt het concept van gerouteerde gebeurtenissen in Windows Presentation Foundation (WPF) beschreven. Het onderwerp definieert terminologie voor gerouteerde gebeurtenissen, beschrijft hoe gerouteerde gebeurtenissen worden gerouteerd via een structuur met elementen, geeft een overzicht van de manier waarop u gerouteerde gebeurtenissen verwerkt en introduceert hoe u uw eigen aangepaste gerouteerde gebeurtenissen maakt.
Voorwaarden
In dit onderwerp wordt ervan uitgegaan dat u basiskennis hebt van de COMMON Language Runtime (CLR) en objectgeoriënteerde programmering, evenals het concept van hoe de relaties tussen WPF-elementen kunnen worden geconceptualiseerd als een structuur. Als u de voorbeelden in dit onderwerp wilt volgen, moet u ook XAML (Extensible Application Markup Language) begrijpen en weten hoe u zeer eenvoudige WPF-toepassingen of -pagina's schrijft. Zie Walkthrough: Mijn eerste WPF-bureaubladtoepassing en XAML in WPF-voor meer informatie.
Wat is een gerouteerde gebeurtenis?
Je kunt nadenken over gerouteerde gebeurtenissen vanuit een functioneel of implementatieperspectief. Beide definities worden hier weergegeven, omdat sommige personen een of de andere definitie nuttiger vinden.
Functionele definitie: Een gerouteerde gebeurtenis is een type gebeurtenis dat handlers kan aanroepen op meerdere listeners in een elementstructuur, in plaats van alleen op het object dat de gebeurtenis heeft gegenereerd.
Implementatiedefinitie: Een gerouteerde gebeurtenis is een CLR-gebeurtenis die wordt ondersteund door een exemplaar van de RoutedEvent-klasse en wordt verwerkt door het WPF-gebeurtenissysteem (Windows Presentation Foundation).
Een typische WPF-toepassing bevat veel elementen. Of deze nu in code zijn gemaakt of gedeclareerd in XAML, deze elementen bestaan in een elementstructuurrelatie met elkaar. De gebeurtenisroute kan zich in een van de twee richtingen verplaatsen, afhankelijk van de gebeurtenisdefinitie, maar over het algemeen beweegt de route van het bronelement en 'bubbelt' omhoog door de elementenboom totdat deze de wortel van de elementenboom bereikt (meestal een pagina of een venster). Dit bubblingconcept is mogelijk bekend als u eerder met het DHTML-objectmodel hebt gewerkt.
Houd rekening met de volgende eenvoudige elementstructuur:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>
Deze elementstructuur produceert ongeveer als volgt:
In deze vereenvoudigde elementstructuur is de bron van een Click-gebeurtenis een van de Button-elementen, en welk Button-element ook wordt aangeklikt, is het eerste element dat de kans heeft om de gebeurtenis te verwerken. Maar als er geen handler aan de Button is gekoppeld en op de gebeurtenis reageert, zal de gebeurtenis doorgegeven worden aan de bovenliggende Button in de elementstructuur, namelijk de StackPanel. Mogelijk bubbelt de gebeurtenis naar Borderen vervolgens verder naar de paginawortel van de elementboom (niet getoond).
Met andere woorden: de gebeurtenisroute voor deze Click gebeurtenis is:
Knop-->StackPanel-->Rand-->...
Scenario's op het hoogste niveau voor gerouteerde gebeurtenissen
Hier volgt een kort overzicht van de scenario's die het gerouteerde gebeurtenisconcept hebben gemotiveerd en waarom een typische CLR-gebeurtenis niet geschikt was voor deze scenario's:
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. De toegevoegde afbeelding mag echter het gedrag voor het detecteren van treffers niet verstoren waardoor een knop reageert op een Click van de inhoud, zelfs als de gebruiker op pixels klikt die technisch gezien deel uitmaken van de afbeelding.
Enkelvoudige handlerbijlagepunten: In Windows Forms moet u dezelfde handler meerdere keren koppelen om gebeurtenissen te verwerken die uit meerdere elementen kunnen worden gegenereerd. Met gerouteerde gebeurtenissen kunt u die handler slechts één keer koppelen, zoals is weergegeven in het vorige voorbeeld en handlerlogica gebruiken om te bepalen waar de gebeurtenis vandaan komt, indien nodig. Dit kan bijvoorbeeld de handler zijn voor de eerder getoonde XAML:
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}
Private Sub CommonClickHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim feSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
Select Case feSource.Name
Case "YesButton"
' do something here ...
Case "NoButton"
' do something ...
Case "CancelButton"
' do something ...
End Select
e.Handled=True
End Sub
Klasseafhandeling: Gerouteerde gebeurtenissen staan een statische handler toe die door de klasse is gedefinieerd. Deze klasse heeft de mogelijkheid om een gebeurtenis te verwerken voordat gekoppelde exemplaarhandlers dat kunnen.
Verwijzen naar een gebeurtenis zonder reflectie: Bepaalde code- en markeringstechnieken vereisen een manier om een specifieke gebeurtenis te identificeren. Een gerouteerde gebeurtenis creëert een RoutedEvent-veld als identificator, wat een robuuste techniek voor gebeurtenisidentificatie biedt waarbij geen statische of runtime-reflectie nodig is.
Hoe gerouteerde gebeurtenissen worden geïmplementeerd
Een gerouteerde gebeurtenis is een CLR-gebeurtenis die wordt ondersteund door een instantie van de klasse RoutedEvent en is geregistreerd bij het WPF-gebeurtenissysteem. De RoutedEvent instantie die is verkregen uit de registratie, wordt doorgaans bewaard als public
static
readonly
veldlid van de klasse die de gerouteerde gebeurtenis registreert en dus 'eigenaar' is van de gerouteerde gebeurtenis. De verbinding met de identieke CLR-gebeurtenis (die soms de 'wrapper'-gebeurtenis wordt genoemd) wordt uitgevoerd door de add
- en remove
-implementaties voor de CLR-gebeurtenis te overschrijven. Normaal gesproken worden de add
en remove
overgelaten als een impliciete standaardwaarde die gebruikmaakt van de juiste taalspecifieke gebeurtenissyntaxis voor het toevoegen en verwijderen van handlers van die gebeurtenis. 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 ziet u de definitie voor een aangepaste Tap
-gerouteerde gebeurtenis, inclusief de registratie en het beschikbaar maken van de RoutedEvent-identificator en de implementaties add
en remove
voor de Tap
CLR-gebeurtenis.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))
' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
Me.AddHandler(TapEvent, value)
End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
Me.RemoveHandler(TapEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.RaiseEvent(e)
End RaiseEvent
End Event
Gerouteerde gebeurtenisafhandelaars en XAML
Als u een handler voor een gebeurtenis wilt toevoegen met XAML, declareert u de gebeurtenisnaam als een kenmerk op het element dat een gebeurtenislistener is. De waarde van het kenmerk is de naam van de geïmplementeerde handlermethode, die moet bestaan in de gedeeltelijke klasse van het code-behind-bestand.
<Button Click="b1SetColor">button</Button>
De XAML-syntax voor het toevoegen van standaard CLR-gebeurtenishandlers is dezelfde als voor het toevoegen van gerouteerde gebeurtenishandlers, omdat u eigenlijk handlers toevoegt aan de CLR-gebeurteniswrapper, die eronder een implementatie van een gerouteerde gebeurtenis heeft. Zie XAML in WPFvoor meer informatie over het toevoegen van gebeurtenis-handlers in XAML.
Routeringsstrategieën
Gerouteerde gebeurtenissen maken gebruik van een van de drie routeringsstrategieën:
Bubbling: Gebeurtenishandlers op de gebeurtenisbron worden aangeroepen. De gerouteerde gebeurtenis routeert vervolgens naar opeenvolgende elementen totdat de wortel van de elementenboom wordt bereikt. De meeste gerouteerde gebeurtenissen maken gebruik van de bubbling-routeringstrategie. Bubbling gerouteerde gebeurtenissen worden over het algemeen gebruikt om wijzigingen in invoer of status van afzonderlijke bedieningselementen of andere elementen van de gebruikersinterface te rapporteren.
Direct: Alleen het bronelement zelf krijgt de mogelijkheid om handlers aan te roepen als reactie. Dit is vergelijkbaar met de routering die Door Windows Forms wordt gebruikt voor gebeurtenissen. In tegenstelling tot standaard CLR-gebeurtenissen bieden directe gerouteerde gebeurtenissen echter ondersteuning voor klasseafhandeling (klasseafhandeling wordt uitgelegd in een volgende sectie) en kunnen ze worden gebruikt door EventSetter en EventTrigger.
Tunneling: In eerste instantie worden gebeurtenishandlers bij de wortel van de elementboom aangeroepen. De gerouteerde gebeurtenis gaat vervolgens door een route via opeenvolgende kindelementen naar het knooppuntelement dat de bron van de gerouteerde gebeurtenis is (het element dat de gerouteerde gebeurtenis heeft veroorzaakt). Tunnelende gerouteerde gebeurtenissen worden vaak gebruikt of verwerkt als onderdeel van de opbouw van een controle-element, zodat gebeurtenissen van samengestelde componenten opzettelijk kunnen worden onderdrukt of vervangen door gebeurtenissen die specifiek zijn voor het volledige controle-element. Invoerevenementen die in WPF beschikbaar worden gesteld, worden vaak geïmplementeerd als een tunneling- en bubblingpaar. Tunneling-gebeurtenissen worden ook wel Preview-gebeurtenissen genoemd, vanwege de benamingsconventie die voor de paren wordt gebruikt.
Waarom gerouteerde gebeurtenissen gebruiken?
Als ontwikkelaar van toepassingen hoeft u niet altijd te weten of te zorgen 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 waar deze wordt gegenereerd.
Wanneer gerouteerde gebeurtenissen krachtig worden, is als u een van de voorgestelde scenario's gebruikt: algemene handlers definiëren in een gemeenschappelijke basis, uw eigen beheerelement samenstellen, of uw eigen aangepaste beheerelementklasse definiëren.
Gerouteerde gebeurtenislisteners en gerouteerde gebeurtenisbronnen hoeven geen gemeenschappelijke gebeurtenis in hun hiërarchie te delen. Elke UIElement of ContentElement kan een gebeurtenislistener zijn voor elke gerouteerde gebeurtenis. Daarom kunt u de volledige set gerouteerde gebeurtenissen die beschikbaar zijn in de werkende API-set gebruiken als een conceptuele 'interface', waarbij verschillende elementen in de toepassing gebeurtenisgegevens kunnen uitwisselen. Dit 'interface'-concept voor gerouteerde gebeurtenissen is met name van toepassing op invoergebeurtenissen.
Gerouteerde gebeurtenissen kunnen ook worden gebruikt om te communiceren via de elementstructuur, omdat de gebeurtenisgegevens voor de gebeurtenis voor elk element in de route blijven bestaan. Eén element kan iets in de gebeurtenisgegevens wijzigen en die wijziging zou beschikbaar zijn voor het volgende element in de route.
Behalve het routeringsaspect zijn er twee andere redenen waarom een bepaalde WPF-gebeurtenis kan worden geïmplementeerd als een gerouteerde gebeurtenis in plaats van een standaard CLR-gebeurtenis. Als u uw eigen gebeurtenissen implementeert, kunt u ook rekening houden met de volgende principes:
Bepaalde styling- en sjablonenfuncties van WPF, zoals EventSetter en EventTrigger, vereisen dat de gebeurtenis waarnaar wordt verwezen een gerouteerde gebeurtenis is. Dit is het gebeurtenis-ID scenario dat eerder is genoemd.
Gerouteerde gebeurtenissen ondersteunen een mechanisme voor klasseafhandeling waarbij de klasse statische methoden kan opgeven die de mogelijkheid hebben om gerouteerde gebeurtenissen af te handelen voordat eventuele geregistreerde instantie-handlers toegang hebben tot deze methoden. Dit is erg handig in het ontwerp van besturingselementen, omdat uw klasse gebeurtenisgestuurd klassegedrag kan afdwingen dat niet per ongeluk kan worden onderdrukt door een gebeurtenis op een exemplaar te verwerken.
Elk van de bovenstaande overwegingen wordt besproken in een afzonderlijke sectie van dit onderwerp.
Een gebeurtenis-handler toevoegen en implementeren voor een gerouteerde gebeurtenis
Als u een gebeurtenis-handler wilt toevoegen in XAML, voegt u de gebeurtenisnaam toe aan een element als kenmerk en stelt u de kenmerkwaarde in als de naam van de gebeurtenis-handler waarmee een geschikte gemachtigde wordt geïmplementeerd, zoals in het volgende voorbeeld.
<Button Click="b1SetColor">button</Button>
b1SetColor
is de naam van de geïmplementeerde handler die de code bevat die de Click gebeurtenis verwerkt.
b1SetColor
moet dezelfde handtekening hebben als de RoutedEventHandler gedelegeerde. Dit is de gemachtigde van de gebeurtenis-handler voor de Click gebeurtenis. De eerste parameter van alle delegaten van de gerouteerde eventhandler specificeert het element waaraan de eventhandler wordt toegevoegd, en de tweede parameter specificeert de gegevens voor de gebeurtenis.
void b1SetColor(object sender, RoutedEventArgs args)
{
//logic to handle the Click event
}
Private Sub b1SetColor(ByVal sender As Object, ByVal args As RoutedEventArgs)
'logic to handle the Click event
End Sub
RoutedEventHandler is de basis-handler voor gerouteerde gebeurtenissen. Voor gerouteerde gebeurtenissen die zijn gespecialiseerd voor bepaalde besturingselementen of scenario's, kunnen de gemachtigden die voor de gerouteerde gebeurtenis-handlers moeten worden gebruikt, ook meer gespecialiseerd worden, zodat ze gespecialiseerde gebeurtenisgegevens kunnen verzenden. In een veelvoorkomend invoerscenario kunt u bijvoorbeeld een DragEnter-gebeurtenis met routing afhandelen. De DragEventHandler-gedelegeerde moet geïmplementeerd worden door je handler. Met behulp van de meest specifieke gedelegeerde kunt u DragEventArgs in de handler verwerken en de eigenschap Data lezen, die de gegevens van het klembord van de sleepbewerking bevat.
Zie Een gerouteerde gebeurtenisverwerken voor een volledig voorbeeld van het toevoegen van een gebeurtenis-handler aan een element met behulp van XAML.
Het toevoegen van een handler voor een gerouteerde gebeurtenis in een toepassing die in code is gemaakt, is eenvoudig. Gerouteerde gebeurtenis-handlers kunnen altijd worden toegevoegd via een helpermethode AddHandler (dit is dezelfde methode als de bestaande back-upoproepen voor add
.) Bestaande WPF-gerouteerde gebeurtenissen hebben over het algemeen backing-implementaties van add
en remove
logica waarmee de handlers voor gerouteerde gebeurtenissen kunnen worden toegevoegd door een taalspecifieke gebeurtenissyntaxis, wat intuïtievere syntaxis is dan de helpermethode. Hier volgt een voorbeeld van het gebruik van de helpermethode:
void MakeButton()
{
Button b2 = new Button();
b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
}
void Onb2Click(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
Private Sub MakeButton()
Dim b2 As New Button()
b2.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf Onb2Click))
End Sub
Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
'logic to handle the Click event
End Sub
In het volgende voorbeeld ziet u de syntaxis van de C#-operator (Visual Basic heeft iets andere operatorsyntaxis vanwege de manier waarop het omgaat met dereferencing):
void MakeButton2()
{
Button b2 = new Button();
b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
Private Sub MakeButton2()
Dim b2 As New Button()
AddHandler b2.Click, AddressOf Onb2Click2
End Sub
Private Sub Onb2Click2(ByVal sender As Object, ByVal e As RoutedEventArgs)
'logic to handle the Click event
End Sub
Zie Een gebeurtenis-handler toevoegen met behulp van codevoor een voorbeeld van het toevoegen van een gebeurtenis-handler in code.
Als u Visual Basic gebruikt, kunt u ook het trefwoord Handles
gebruiken om handlers toe te voegen als onderdeel van de handlerdeclaraties. Zie Visual Basic en WPF Event Handlingvoor meer informatie.
Het concept van afhandeling
Alle gerouteerde gebeurtenissen delen een algemene gegevensdatabaseklasse voor gebeurtenissen, RoutedEventArgs.
RoutedEventArgs definieert de eigenschap Handled, die een Booleaanse waarde gebruikt. Het doel van de eigenschap Handled is om een event handler langs de route in staat te stellen de gerouteerde gebeurtenis als afgehandeldte markeren door de waarde van Handled in te stellen op true
. Nadat de handler op één element langs de route is verwerkt, worden de gedeelde gebeurtenisgegevens opnieuw gerapporteerd aan elke listener langs de route.
De waarde van Handled beïnvloedt hoe een gerouteerde gebeurtenis wordt gerapporteerd of verwerkt wanneer deze verder langs de route gaat. Als Handled is true
in de gebeurtenisgegevens voor een gerouteerde gebeurtenis, worden handlers die luisteren naar die gerouteerde gebeurtenis op andere elementen doorgaans niet meer aangeroepen voor dat specifieke gebeurtenisvoorbeeld. Dit geldt zowel voor handlers die zijn gekoppeld in XAML als voor handlers die zijn toegevoegd door taalspecifieke gebeurtenishandlerbijlagen, zoals +=
of Handles
. Voor de meest voorkomende handlerscenario's markeert u een gebeurtenis als verwerkt door Handled in te stellen op true
. Hiermee stopt de routering voor een tunnelroute of een bubbelende route, en ook voor elke gebeurtenis die op een punt in de route door een klasse-handler wordt verwerkt.
Er is echter een 'handledEventsToo'-mechanisme waarbij listeners nog steeds handlers kunnen uitvoeren als reactie op gerouteerde gebeurtenissen waarbij Handled wordt true
in de gebeurtenisgegevens. Met andere woorden, de gebeurtenisroute wordt niet daadwerkelijk gestopt door de gebeurtenisgegevens aan te geven als verwerkt. U kunt het handledEventsToo-mechanisme alleen gebruiken in code of in een EventSetter:
In code roept u in plaats van een taalspecifieke gebeurtenissyntaxis te gebruiken die geschikt is voor algemene CLR-gebeurtenissen, de WPF-methode aan AddHandler(RoutedEvent, Delegate, Boolean) om uw handler toe te voegen. Geef de waarde van
handledEventsToo
op alstrue
.Stel in een EventSetterhet kenmerk HandledEventsToo in op
true
.
Naast het gedrag dat Handled status produceert in gerouteerde gebeurtenissen, heeft het concept van Handled gevolgen voor het ontwerpen van uw toepassing en het schrijven van de gebeurtenis-handlercode. U kunt Handled conceptualiseren als een eenvoudig protocol dat via gerouteerde gebeurtenissen wordt weergegeven. Precies hoe u dit protocol gebruikt, is aan u, maar het conceptuele ontwerp voor hoe de waarde van Handled moet worden gebruikt, is als volgt:
Als een gerouteerde gebeurtenis als afgehandeld is gemarkeerd, hoeft deze niet opnieuw te worden afgehandeld door andere elementen op die route.
Als een gerouteerde gebeurtenis niet is gemarkeerd als verwerkt, hebben andere listeners die eerder op de route stonden gekozen om geen handler te registreren, of de handlers die zijn geregistreerd, hebben ervoor gekozen om de gebeurtenisgegevens niet te bewerken en Handled in te stellen op
true
. (Of het is natuurlijk mogelijk dat de huidige listener het eerste punt in de route is.) Handlers op de huidige listener hebben nu drie mogelijke acties:Helemaal geen actie ondernemen; de gebeurtenis blijft onverwerkt en wordt doorgestuurd naar de volgende luisteraar.
Voer code uit als reactie op de gebeurtenis, maar zorg ervoor dat de actie die is ondernomen, niet aanzienlijk genoeg is om te garanderen dat de gebeurtenis wordt gemarkeerd als afgehandeld. De gebeurtenis wordt gerouteerd naar de volgende listener.
Voer code uit als reactie op de gebeurtenis. Markeer de gebeurtenis als afgehandeld in de gegevens die naar de handler zijn doorgegeven, omdat de actie die is ondernomen aanzienlijk genoeg is om afhandeling te rechtvaardigen. De gebeurtenis wordt nog steeds gerouteerd naar de volgende listener, maar met Handled=
true
in de gebeurtenisgegevens, hebben alleenhandledEventsToo
listeners de mogelijkheid om verdere handlers aan te roepen.
Dit conceptuele ontwerp wordt versterkt door het eerder genoemde routeringsgedrag: het is moeilijker (hoewel nog steeds mogelijk in code of stijlen) om handlers te koppelen voor gerouteerde gebeurtenissen die worden aangeroepen, zelfs als een eerdere handler langs de route al Handled heeft ingesteld op true
.
Zie voor meer informatie over Handled, de klasseafhandeling van gerouteerde gebeurtenissen en aanbevelingen over wanneer het gepast is om een gerouteerde gebeurtenis als Handledte markeren, de sectie "Gerouteerde gebeurtenissen markeren als verwerkt" en de sectie over klasseafhandeling.
In toepassingen is het gebruikelijk om alleen een opborrelend gerouteerd evenement af te handelen op het object dat het heeft veroorzaakt, en zich helemaal niet bezig te houden met de routeringskenmerken van het evenement. Het is echter nog steeds een goede gewoonte om de gerouteerde gebeurtenis te markeren zoals verwerkt in de gebeurtenisgegevens, om onverwachte bijwerkingen te voorkomen, voor het geval een element dat zich verder in de elementstructuur bevindt, ook een handler heeft gekoppeld voor diezelfde gerouteerde gebeurtenis.
Klassehandlers
Als u een klasse definieert die op een of andere manier is afgeleid van DependencyObject, kunt u ook een klasse-handler definiëren en koppelen voor een gerouteerde gebeurtenis die een gedeclareerd of overgenomen gebeurtenislid van uw klasse is. Klasse-handlers worden aangeroepen voordat eventlistener-handlers die gekoppeld zijn aan een exemplaar van die klasse worden aangeroepen, wanneer een gerouteerde gebeurtenis een elementexemplaar in de route bereikt.
Sommige WPF-besturingselementen hebben inherente klasseafhandeling voor bepaalde gerouteerde gebeurtenissen. Dit kan de indruk wekken dat de gerouteerde gebeurtenis nooit wordt gegenereerd, maar in werkelijkheid wordt deze door de klasse afgehandeld en kan de gerouteerde gebeurtenis mogelijk nog steeds worden verwerkt door uw instance handlers als u bepaalde technieken gebruikt. Veel basisklassen en besturingselementen bieden ook virtuele methoden weer die kunnen worden gebruikt om gedrag van klasseafhandeling te overschrijven. Raadpleeg Gerouteerde Gebeurtenissen Markeren als Verwerkt en Klassenafhandelingvoor meer informatie over het omzeilen van ongewenste klassenafhandeling en het definiëren van uw eigen klassenafhandeling in een aangepaste klasse.
Gekoppelde gebeurtenissen in WPF
De XAML-taal definieert ook een speciaal type gebeurtenis dat een gekoppelde gebeurteniswordt genoemd. Met een gekoppelde gebeurtenis kunt u een handler voor een bepaalde gebeurtenis toevoegen aan een willekeurig element. Het element dat de gebeurtenis verwerkt, hoeft de gekoppelde gebeurtenis niet te definiëren of over te nemen, en noch het object dat mogelijk de gebeurtenis veroorzaakt, noch het doeleinde dat de gebeurtenis afhandelt, moeten deze gebeurtenis definiëren of op een andere manier 'eigenaar' zijn van die gebeurtenis als een lid van een klasse.
Het WPF-invoersysteem maakt uitgebreid gebruik van gekoppelde gebeurtenissen. Bijna al deze gekoppelde gebeurtenissen worden echter doorgestuurd via basiselementen. De invoergebeurtenissen worden vervolgens weergegeven als gelijkwaardige niet-gekoppelde gerouteerde gebeurtenissen die lid zijn van de basiselementklasse. De onderliggende gekoppelde gebeurtenis Mouse.MouseDown kan bijvoorbeeld eenvoudiger worden verwerkt op een bepaalde UIElement met behulp van MouseDown op die UIElement in plaats van de gekoppelde gebeurtenissyntaxis in XAML of code te verwerken.
Zie Overzicht van gekoppelde gebeurtenissenvoor meer informatie over gekoppelde gebeurtenissen in WPF.
Gekwalificeerde gebeurtenisnamen in XAML
Een ander syntaxisgebruik dat lijkt op typenaam.gebeurtenisnaam syntaxis van gekoppelde gebeurtenissen, maar is niet strikt genomen een gekoppeld gebeurtenisgebruik wanneer u handlers koppelt voor gerouteerde gebeurtenissen die worden gegenereerd door onderliggende elementen. U koppelt de handlers aan een gemeenschappelijke bovenliggende element om te profiteren van gebeurtenisroutering, ook al heeft het gemeenschappelijke bovenliggende element mogelijk niet de relevante gerouteerde gebeurtenis als element. Bekijk dit voorbeeld opnieuw:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>
Hier is de listener van het bovenliggende element waar de handler wordt toegevoegd een StackPanel. Er wordt echter een handler toegevoegd voor een gerouteerde gebeurtenis die is gedeclareerd en wordt gegenereerd door de Button klasse (ButtonBase eigenlijk, maar beschikbaar voor Button via overname). Button is eigenaar van de gebeurtenis, maar het gerouteerde gebeurtenissysteem staat toe dat handlers worden gekoppeld aan elke UIElement- of ContentElement-instantieluisteraar die anders luisteraars zou kunnen koppelen voor een CLR-gebeurtenis (Common Language Runtime). De standaard-XMLNS-naamruimte 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 XAMLvoor meer informatie over xmlns.
WPF-invoerevenementen
Een frequente toepassing van gerouteerde gebeurtenissen binnen het WPF-platform is voor invoergebeurtenissen. In WPF worden de namen van tunnelgerouteerde gebeurtenissen volgens conventie voorafgegaan door het woord 'Preview'. Invoergebeurtenissen komen vaak in paren voor, waarbij de ene gebeurtenis de bubblinggebeurtenis is en de andere de tunnelinggebeurtenis is. De KeyDown-gebeurtenis en de PreviewKeyDown-gebeurtenis hebben bijvoorbeeld dezelfde handtekening, waarbij de eerste de bubbelen-invoergebeurtenis is en de laatste de doordringend-invoergebeurtenis. Soms hebben invoergebeurtenissen alleen een bubbelversie of misschien alleen een direct gerouteerde versie. In de documentatie verwijzen gerouteerde gebeurtenisonderwerpen kruislings naar vergelijkbare gerouteerde gebeurtenissen met alternatieve routeringsstrategieën als dergelijke gerouteerde gebeurtenissen bestaan, en secties op de beheerde referentiepagina's verduidelijken de routeringsstrategie van elke gerouteerde gebeurtenis.
nl-NL: WPF-invoergebeurtenissen die in paren voorkomen, worden zodanig geïmplementeerd dat een enkele gebruikersactie vanuit de invoer, zoals het indrukken van een muisknop, beide gerouteerde gebeurtenissen van het paar opeenvolgend activeert. Eerst wordt de tunneling-gebeurtenis gegenereerd en wordt de route afgelegd. Vervolgens wordt het bubbelproces gegenereerd en volgt het zijn route. De twee gebeurtenissen delen letterlijk dezelfde gebeurtenisgegevensinstantie, omdat de RaiseEvent methode-aanroep in de implementerende klasse die de bubbling gebeurtenis genereert, luistert naar de gebeurtenisgegevens van de tunneling-gebeurtenis en deze opnieuw gebruikt in het nieuw opgeworpen evenement. Listeners met handlers voor de tunneling-gebeurtenis hebben de eerste mogelijkheid om de gerouteerde gebeurtenis te markeren (klassehandlers eerst en vervolgens instantiehandlers). Als een element langs de tunnelingroute de gerouteerde gebeurtenis als afgehandeld heeft gemarkeerd, worden de al afgehandelde gebeurtenisgegevens doorgegeven voor de bubbling-gebeurtenis, en zullen de gebruikelijke handlers die aan de equivalente bubbling-invoergebeurtenissen zijn gekoppeld, niet worden aangeroepen. Aan de buitenkant zal het lijken alsof de afgehandelde bubbelgebeurtenis niet eens is opgetreden. Dit afhandelingsgedrag is handig voor controlecompositing, waarbij u mogelijk wilt dat alle invoergebeurtenissen op basis van hittests of focusgebeurtenissen worden gerapporteerd door uw uiteindelijke besturingselement, in plaats van de samengestelde onderdelen. Het laatste besturingselement ligt dichter bij de basis in de samenstelling, en heeft daardoor de kans om als eerste de tunneling-gebeurtenis te verwerken en deze gerouteerde gebeurtenis te vervangen door een meer controlespecifieke gebeurtenis, als onderdeel van de code die de besturingsklasse ondersteunt.
Bekijk het volgende voorbeeld van een invoer gebeurtenis als afbeelding van de werking van de verwerking van invoerevenementen. In het volgende boomschema is leaf element #2
de bron van eerst een PreviewMouseDown
en vervolgens een MouseDown
gebeurtenis.
De volgorde van gebeurtenisverwerking is als volgt:
PreviewMouseDown
(tunnel) op het hoofdelement.PreviewMouseDown
(tunnel) op tussenliggend element #1.PreviewMouseDown
(tunnel) op bronelement 2.MouseDown
(bellen) op bronelement 2.MouseDown
(bellen) op tussenliggend element 1.MouseDown
(bel) op het wortelelement.
Een gedelegeerde voor een gerouteerde gebeurtenis-handler bevat verwijzingen naar twee objecten: het object dat een gebeurtenis heeft opgeroepen en het object waar de handler is aangeroepen. Het object waarin de handler is aangeroepen, is het object dat door de parameter sender
is gerapporteerd. Het object waar de gebeurtenis voor het eerst is gegenereerd, wordt gerapporteerd door de eigenschap Source in de gebeurtenisgegevens. Een gerouteerde gebeurtenis kan nog steeds worden gegenereerd en verwerkt door hetzelfde object. In dat geval zijn sender
en Source identiek (dit is het geval bij stap 3 en 4 in de lijst met voorbeelden van gebeurtenisverwerking).
Vanwege tunneling en bubbling ontvangen ouder elementen invoergebeurtenissen waarbij Source een van hun kindelementen is. Wanneer het belangrijk is om te weten wat het bronelement is, kunt u het bronelement identificeren door toegang te krijgen tot de eigenschap Source.
Wanneer de invoergebeurtenis is gemarkeerd als Handled, worden er meestal geen verdere handlers aangeroepen. Normaal gesproken moet u invoergebeurtenissen markeren als verwerkt zodra een handler wordt aangeroepen die betrekking heeft op de toepassingsspecifieke logische verwerking van de betekenis van de invoergebeurtenis.
De uitzondering op deze algemene verklaring over de Handled status is dat invoergebeurtenis-handlers die zijn geregistreerd om opzettelijk de Handled status van de gebeurtenisgegevens te negeren, toch langs één van beide routes worden aangeroepen. Zie Preview-gebeurtenissen of Gerouteerde gebeurtenissen markeren als verwerkt en klasseafhandelingvoor meer informatie.
Het gedeelde gebeurtenisgegevensmodel tussen tunneling en bubblinggebeurtenissen, en de opeenvolgende verhoging van eerste tunneling en vervolgens bubblinggebeurtenissen, is geen concept dat over het algemeen waar is voor alle gerouteerde gebeurtenissen. Dit gedrag wordt specifiek geïmplementeerd door de wijze waarop WPF-invoerapparaten ervoor kiezen om de invoergebeurtenisparen te genereren en te verbinden. Het implementeren van uw eigen invoerevenementen is een geavanceerd scenario, maar u kunt ervoor kiezen om dat model ook te volgen voor uw eigen invoerevenementen.
Bepaalde klassen verwerken bepaalde invoergebeurtenissen, meestal met de intentie om een gebruikersgestuurde invoergebeurtenis binnen dat besturingselement opnieuw te definiëren en een nieuwe gebeurtenis te genereren. Zie Gerouteerde gebeurtenissen markeren als verwerkt en klasseafhandelingvoor meer informatie.
Zie Input Overviewvoor meer informatie over invoer en hoe invoer en gebeurtenissen communiceren in typische toepassingsscenario's.
EventSetters en EventTriggers
In stijlen kunt u een aantal vooraf gedeclareerde XAML-gebeurtenisverwerkingssyntaxis in de markup opnemen met behulp van een EventSetter. Wanneer de stijl wordt toegepast, wordt de genoemde handler toegevoegd aan de gestijlde instantie. U kunt een EventSetter alleen declareren voor een gerouteerde gebeurtenis. Hier volgt een voorbeeld. De b1SetColor
methode waarnaar hier wordt verwezen, bevindt zich in een code-behind-bestand.
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.EventOvw2"
Name="dpanel2"
Initialized="PrimeHandledToo"
>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="b1SetColor"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Name="ThisButton" Click="HandleThis">
Raise event, handle it, use handled=true handler to get it anyway.
</Button>
</StackPanel>
Het voordeel dat hier is opgedaan, is dat de stijl waarschijnlijk veel andere informatie bevat die van toepassing kan zijn op een knop in uw toepassing en dat de EventSetter deel uitmaken van die stijl het hergebruik van code bevordert, zelfs op het niveau van markeringen. Bovendien abstraheert een EventSetter methodenamen voor handlers nog een stap verder van de algemene applicatie en paginacode.
Een andere gespecialiseerde syntaxis die de gerouteerde gebeurtenis- en animatiefuncties van WPF combineert, is een EventTrigger. Net als bij EventSetterkunnen alleen gerouteerde gebeurtenissen worden gebruikt voor een EventTrigger. Normaal gesproken wordt een EventTrigger gedeclareerd als onderdeel van een stijl, maar een EventTrigger kan ook 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 ten opzichte van het enkel afhandelen van de gebeurtenis en het starten van een bestaand storyboard, is dat een EventTrigger betere controle biedt over het storyboard en het run-time gedrag. Zie Gebeurtenistriggers gebruiken om een Storyboard te beheren nadat deze is gestartvoor meer informatie.
Meer informatie over gerouteerde gebeurtenissen
In dit onderwerp worden voornamelijk gerouteerde gebeurtenissen besproken vanuit het perspectief van het beschrijven van de basisconcepten en het aanbieden van richtlijnen over hoe en wanneer moet worden gereageerd op de gerouteerde gebeurtenissen die al aanwezig zijn in de verschillende basiselementen en besturingselementen. U kunt echter uw eigen geconfigureerde gebeurtenis creëren in uw aangepaste klasse, samen met alle benodigde ondersteuning, zoals gespecialiseerde klassen voor gebeurtenisgegevens en gedelegeerden. De eigenaar van de 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