Översikt över routade händelser (WPF .NET)
Programutvecklare och komponentförfattare i Windows Presentation Foundation (WPF) kan använda dirigerade händelser för att sprida händelser via ett elementträd och anropa händelsehanterare på flera lyssnare i trädet. Dessa funktioner finns inte i vanliga CLR-händelser (Language Runtime). Flera WPF-händelser är routade händelser, till exempel ButtonBase.Click. Den här artikeln beskriver grundläggande begrepp för dirigerade händelser och ger vägledning om när och hur du svarar på routade händelser.
Förutsättningar
Den här artikeln förutsätter grundläggande kunskaper om CLR (Common Language Runtime), objektorienterad programmering och hur WPF-elementlayout kan konceptualiseras som ett träd. Om du vill följa exemplen i den här artikeln hjälper det om du är bekant med XAML (Extensible Application Markup Language) och vet hur du skriver WPF-program.
Vad är en routad händelse?
Du kan överväga routade händelser ur ett funktionellt perspektiv eller implementeringsperspektiv:
Från ett funktionellt perspektiv är en dirigerad händelse en typ av händelse som kan anropa hanterare hos flera lyssnare i ett elementträd, inte bara vid händelsekällan. En händelselyssnare är det element där en händelsehanterare är ansluten och anropad. En händelsekälla är det element eller objekt som ursprungligen skapade en händelse.
Från en implementering perspektiv är en dirigerad händelse en händelse som registrerats med WPF-händelsesystemet, som backas upp av en instans av klassen RoutedEvent och bearbetas av WPF-händelsesystemet. Vanligtvis implementeras en dirigerad händelse med en CLR-händelse-"wrapper" för att aktivera händelsehanterare i XAML och i kod-bakom precis som du skulle göra med en CLR-händelse.
WPF-program innehåller vanligtvis många element, som antingen deklarerades i XAML eller instansieras i kod. Ett programs element finns i dess elementträd. Beroende på hur en dirigerad händelse definieras, när händelsen aktiveras på ett källelement:
- Bubblar upp genom elementträdet från källelementet till rotelementet, som vanligtvis är en sida eller ett fönster.
- Tunnlar nedåt genom elementträdet från rotelementet till källelementet.
- Färdas inte genom elementträdet och sker bara på källelementet.
Överväg följande partiella elementträd:
<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>
Elementträdet renderas enligt följande:
Var och en av de tre knapparna är en potentiell Click händelsekälla. När man klickar på en av knapparna utlöses händelsen Click
, som bubblar upp från knappen till roten. Elementen Button och Border har inte händelsehanterare kopplade, men StackPanel har det. Eventuellt har andra element högre upp i trädet, som inte visas, också Click
händelsehanterare anslutna. När händelsen Click
når StackPanel
-elementet anropar WPF-händelsesystemet den YesNoCancelButton_Click
-hanterare som är kopplad till den. Händelsevägen för händelsen Click
i exemplet är: Button
–>StackPanel
–>Border
–> efterföljande överordnade element.
Anmärkning
Elementet som ursprungligen genererade en dirigerad händelse identifieras som RoutedEventArgs.Source i händelsehanterarparametrarna. Händelselyssnaren är det element där händelsehanteraren är ansluten och anropad och identifieras som avsändare i händelsehanterarparametrarna.
Scenarier på toppnivå för routade händelser
Här är några av de scenarier som motiverade begreppet dirigerad händelse och skiljer det från en typisk CLR-händelse:
Kontrollsammansättning och inkapsling: Olika kontroller i WPF har en omfattande innehållsmodell. Du kan till exempel placera en bild i en Button, som effektivt utökar knappens visuella träd. Men den tillagda bilden får inte bryta träfftestbeteendet för knappen, som måste svara när en användare klickar på bildpunkterna.
Enhetliga hanterarpunkter: Du kan registrera en hanterare för varje knapps
Click
händelse, men med routade händelser kan du koppla en enda hanterare enligt föregående XAML-exempel. På så sätt kan du ändra elementträdet under singularhanteraren, till exempel lägga till eller ta bort fler knappar, utan att behöva registrera varje knappsClick
händelse. När denClick
händelsen aktiveras kan hanterarlogik avgöra var händelsen kom ifrån. Följande hanterare, som angavs i det tidigare visade XAML-elementträdet, innehåller den logiken: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
Klasshantering: Routade händelser stöder en klasshändelsehanterare som du definierar i en klass. Klasshanterare hanterar en händelse innan någon instanshanterare hanterar samma händelse på en instans av klassen.
Referera till en händelse utan reflektion: Varje dirigerad händelse skapar en RoutedEvent fältidentifierare för att erbjuda en robust metod för händelseidentifiering som inte kräver statisk eller dynamisk reflektion för att identifiera händelsen.
Så implementeras routade händelser
En dirigerad händelse är en händelse som registrerats med WPF-händelsesystemet, som backas upp av en instans av klassen RoutedEvent och bearbetas av WPF-händelsesystemet. Instansen RoutedEvent
, som hämtas från registrering, lagras typiskt som en medlem av public static readonly
i klassen som registrerade den. Den klassen kallas för händelsens "ägare-klass". Vanligtvis implementerar en ruterad händelse en identiskt namngiven CLR-händelse "omslag". CLR-händelseomslutningen innehåller add
- och remove
-åtkomster för att möjliggöra koppling av hanterare i XAML och i bakomliggande kod via språkspecifik händelsesyntax.
add
- och remove
-accessorerna åsidosätter sin CLR-implementering och anropar de dirigerade händelsemetoderna AddHandler och RemoveHandler. Mekanismen för säkerhetskopiering och anslutning av routade händelser liknar konceptuellt hur en beroendeegenskap är en CLR-egenskap som backas upp av klassen DependencyProperty och registreras med WPF-egenskapssystemet.
I följande exempel registreras den dirigerade händelsen Tap
, och den returnerade instansen RoutedEvent
lagras medan en CLR-händelseomslag implementeras.
// 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
Routningsstrategier
Ruttade händelser använder en av tre ruttstrategier:
Bubbling: Inledningsvis anropas händelsehanterare på händelsekällan. Den dirigerade händelsen rutas sedan till efterföljande överordnade element och anropar deras händelsehanterare i tur och ordning, tills den når elementträdsroten. De flesta routade händelser använder den bubblande routningsstrategin. Bubblande routade händelser används vanligtvis för att rapportera indata- eller tillståndsändringar från sammansatta kontroller eller andra gränssnittselement.
Tunneling: Inledningsvis anropas händelsehanterare i elementträdsroten. Den dirigerade händelsen fortsätter sedan till nästa underordnade element och anropar deras händelsehanterare i tur och ordning tills den når händelsekällan. Händelser som följer en tunnelväg kallas även för förhandsversion händelser. WPF-indatahändelser implementeras vanligtvis som en förhandsversion och bubblande par.
Direct: Endast händelsehanterare på händelsekällan anropas. Den här icke-routningsstrategin motsvarar händelser i Windows Forms UI Framework, som är clr-standardhändelser. Till skillnad från CLR-händelser stöder direktdirigerade händelser klasshantering och kan användas av EventSetters och EventTriggers.
Varför ska du använda routade händelser?
Som programutvecklare behöver du inte alltid veta eller bry dig om att händelsen du hanterar implementeras som en dirigerad händelse. Routade händelser har ett särskilt beteende, men det beteendet är till stor del osynligt om du hanterar en händelse på elementet som skapade den. Routade händelser är dock relevanta när du vill koppla en händelsehanterare till ett överordnat element för att hantera händelser som genereras av underordnade element, till exempel inom en sammansatt kontroll.
Dirigerade händelselyssnare behöver inte de dirigerade händelser som de hanterar för att vara medlemmar i klassen. Vilken som helst av UIElement eller ContentElement kan vara en händelselyssnare för vilken routad händelse som helst. Eftersom visuella element härleds från UIElement
eller ContentElement
kan du använda routade händelser som ett konceptuellt "gränssnitt" som stöder utbyte av händelseinformation mellan olika element i ett program. Begreppet "gränssnitt" för routade händelser gäller särskilt för indatahändelser.
Routade händelser stöder utbyte av händelseinformation mellan element längs händelsevägen eftersom varje lyssnare har åtkomst till samma instans av händelsedata. Om ett element ändrar något i händelsedata visas ändringen för efterföljande element i händelsevägen.
Förutom routningsaspekten kan du välja att implementera en dirigerad händelse i stället för en standard-CLR-händelse av följande skäl:
Vissa WPF-formaterings- och mallfunktioner, till exempel EventSetters och EventTriggers, kräver att den refererade händelsen är en dirigerad händelse.
Routade händelser stöder klassens händelsehanterare som hanterar en händelse före alla instanshanterare för samma händelse på någon instans av lyssnarklassens instanser. Den här funktionen är användbar i kontrolldesignen eftersom din klasshanterare kan framtvinga händelsedrivna klassbeteenden som inte oavsiktligt kan ignoreras av en instanshanterare.
Bifoga och implementera en dirigerad händelsehanterare
I XAML kopplar du en händelsehanterare till ett element genom att deklarera händelsenamnet som ett attribut för händelselyssningselementet. Attributvärdet är namnet på hanterarens metod. Hanteringsmetoden måste implementeras i den delvisa klassen code-behind för XAML-sidan. Händelselyssnaren är det element där händelsehanteraren är ansluten och anropad.
För en händelse som är medlem (ärvd eller på annat sätt) i lyssnarklassen kan du koppla en hanterare på följande sätt:
<Button Name="Button1" Click="Button_Click">Click me</Button>
Om händelsen inte tillhör lyssnarens klass måste du använda det fullständigt kvalificerade händelsenamnet i form av <owner type>.<event name>
. Eftersom klassen StackPanel inte implementerar händelsen Click, behöver du använda syntaxen för kvalificerat händelsenamn för att koppla en hanterare till en StackPanel
för en Click
-händelse som bubblar upp till det elementet.
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
Signaturen för händelsehanterarmetoden i *code-behind* måste matcha delegattypen för den dirigerade händelsen. Parametern sender
för delegerad RoutedEventHandler för evenemanget Click anger det element som händelsehanteraren är kopplad till. Parametern args
för RoutedEventHandler
-ombudet innehåller händelsedata. En kompatibel kod-bakom-implementering för Button_Click
händelsehanterare kan vara:
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
Även om RoutedEventHandler är den grundläggande routed händelsehanterare-delegaten, kräver vissa kontroller eller implementeringsscenarier olika delegater som stöder mer specialiserad händelsedata. Som ett exempel, för den DragEnter dirigerade händelsen bör din hanterare implementera DragEventHandler delegering. På så sätt kan din hanteringskod komma åt egenskapen DragEventArgs.Data i händelsedata, som innehåller nyttolasten från urklippet av dragåtgärden.
XAML-syntaxen för att lägga till routade händelsehanterare är densamma som för standard-CLR-händelsehanterare. Mer information om hur du lägger till händelsehanterare i XAML finns i XAML i WPF. Ett fullständigt exempel på hur du kopplar en händelsehanterare till ett element med XAML finns i Hantera en dirigerad händelse.
Om du vill koppla en händelsehanterare för en dirigerad händelse till ett element med hjälp av kod har du vanligtvis två alternativ:
Anropa metoden AddHandler direkt. Routade händelsehanterare kan alltid kopplas på det här sättet. Det här exemplet kopplar en
Click
händelsehanterare till en knapp med hjälp av metodenAddHandler
:Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
För att koppla en hanterare för knappens
Click
händelse till ett annat element i händelsens flöde, till exempel en StackPanel som heterStackPanel1
.StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
Om den dirigerade händelsen implementerar en CLR-händelseomslutning använder du språkspecifik händelsesyntax för att lägga till händelsehanterare precis som för en standard-CLR-händelse. De flesta befintliga WPF-routade händelser implementerar CLR-omslutningen, vilket möjliggör språkspecifik händelsesyntax. I det här exemplet kopplas en
Click
händelsehanterare till en knapp med hjälp av språkspecifik syntax:Button1.Click += Button_Click;
AddHandler Button1.Click, AddressOf Button_Click
Ett exempel på hur du kopplar en händelsehanterare i kod finns i Så här lägger du till en händelsehanterare med hjälp av kod. Om du kodar i Visual Basic kan du också använda nyckelordet Handles
för att lägga till hanterare som en del av hanterardeklarationerna. Mer information finns i Visual Basic- och WPF-händelsehantering.
Begreppet hantering
Alla routade händelser delar en gemensam basklass för händelsedata, vilket är klassen RoutedEventArgs. Klassen RoutedEventArgs
definierar egenskapen Handled för boolesk. Syftet med egenskapen Handled
är att låta alla händelsehanterare längs händelsevägen markera den dirigerade händelsen som hanterad. Om du vill markera en händelse som hanterad anger du värdet för Handled
till true
i händelsehanterarkoden.
Värdet för Handled
påverkar hur en dirigerad händelse bearbetas när den färdas längs händelsevägen. Om Handled
är true
i delade händelsedata för en dirigerad händelse anropas vanligtvis inte hanterare som är kopplade till andra element längre längs händelsevägen för den specifika händelseinstansen. För de vanligaste hanteringsscenarierna hindrar märkning av en händelse som hanterad effektivt efterföljande hanterare längs händelsevägen, oavsett om det är instans- eller klasshanterare, från att svara på den specifika händelseinstansen. I sällsynta fall där du behöver din händelsehanterare för att svara på dirigerade händelser som har markerats som hanterade kan du dock:
Koppla hanteraren i code-behind med hjälp av AddHandler(RoutedEvent, Delegate, Boolean) överlagring, med parametern
handledEventsToo
inställd påtrue
.Ställ in attributet HandledEventsToo i en
EventSetter
tilltrue
.
Begreppet Handled
kan påverka hur du utformar ditt program och kodar dina händelsehanterare. Du kan konceptualisera Handled
som ett enkelt protokoll för bearbetning av dirigerade händelser. Hur du använder det här protokollet är upp till dig, men den förväntade användningen av parametern Handled
är:
Om en dirigerad händelse markeras som hanterad behöver den inte hanteras igen av andra element längs vägen.
Om en dirigerad händelse inte markeras som hanterad har lyssnarna tidigare i händelsevägen ingen hanterare för händelsen, eller så svarade ingen av de registrerade hanterarna på händelsen på ett sätt som motiverar att händelsen markeras som hanterad. Hanterare på den aktuella lyssnaren har tre möjliga åtgärdsmekanismer:
Vidta inga åtgärder alls. Händelsen förblir ohanterad och dirigeras till nästa lyssnare i trädet.
Kör kod som svar på händelsen, men inte i en omfattning som motiverar att händelsen markeras som hanterad. Händelsen förblir ohanterad och skickas till nästa lyssnare i trädet.
Kör kod som svar på händelsen, i en utsträckning som motiverar att händelsen markeras som hanterad. Markera händelsen som hanterad i händelsedata. Händelsen dirigeras fortfarande till nästa lyssnare i trädet, men de flesta lyssnare anropar inte ytterligare hanterare. Undantaget är lyssnare med hanterare som har registrerats specifikt med
handledEventsToo
inställt påtrue
.
Mer information om hur du hanterar dirigerade händelser finns i Märkning av dirigerade händelser som hanterade och klasshantering.
Även om utvecklare som bara hanterar en bubblande dirigerad händelse på objektet som utlöste den kanske inte bryr sig om andra lyssnare, är det ändå bra praxis att markera händelsen som hanterad. Detta förhindrar oväntade biverkningar om ett element längre längs händelsevägen har en hanterare för samma dirigerade händelse.
Klasshanterare
Routade händelsehanterare kan antingen vara instans--hanterare eller klass--hanterare. Klasshanterare för en viss klass anropas innan någon instanshanterare svarar på samma händelse på någon instans av den klassen. På grund av detta beteende, när dirigerade händelser markeras som hanterade, markeras de ofta som sådana i klasshanterare. Det finns två typer av klasshanterare:
- statiska klasshändelsehanterare, som registreras genom att anropa metoden RegisterClassHandler i en statisk klasskonstruktor.
- Åsidosätt klasshändelsehanterare, som registreras genom att åsidosätta virtuella händelsemetoder för basklass. Virtuella händelsemetoder i basklassen finns främst för inmatningshändelser och har namn som börjar med On<händelsenamn> och OnPreview<händelsenamn>.
Vissa WPF-kontroller har inbyggd klasshantering för vissa routade händelser. Klasshantering kan verka som att den dirigerade händelsen aldrig utlöses, men i själva verket markeras den som hanterad av en klasshanterare. Om du behöver händelsehanteraren för att svara på den hanterade händelsen kan du registrera din hanterare med handledEventsToo
inställd på true
. Mer information om hur du implementerar dina egna klasshanterare eller arbetar med oönskad klasshantering finns i Märkning av dirigerade händelser som hanterade och klasshantering.
Kopplade händelser i WPF
XAML-språket definierar också en särskild typ av händelse som kallas en bifogad händelse. Anslutna händelser kan användas för att definiera en ny dirigerad händelse i en icke-elementklass och generera händelsen på alla element i ditt träd. För att göra det måste du registrera den bifogade händelsen som en routed event och ange specifik stödkod och som stöder funktionen för bifogade händelser. Eftersom anslutna händelser registreras som routade händelser sprids de genom elementträdet när de genereras på ett element.
I XAML-syntax anges en bifogad händelse med dess händelsenamn och ägartyp, i form av <owner type>.<event name>
. Eftersom händelsenamnet är kvalificerat med namnet på dess ägartyp tillåter syntaxen att händelsen kopplas till alla element som kan instansieras. Den här syntaxen gäller även för hanterare för vanliga routade händelser som kopplas till ett godtyckligt element längs händelsevägen. Du kan också koppla hanterare för anslutna händelser i koden bakom genom att anropa metoden AddHandler på objektet som hanteraren ska koppla till.
WPF-indatasystemet använder anslutna händelser i stor utsträckning. Nästan alla av dessa anslutna händelser visas dock som motsvarande icke-anslutna rutade händelser via basobjekt. Du använder eller hanterar sällan anslutna händelser direkt. Det är till exempel enklare att hantera den underliggande kopplade Mouse.MouseDown händelsen på en UIElement via motsvarande UIElement.MouseDown dirigerad händelse än med hjälp av kopplad händelsesyntax i XAML eller bakomliggande kod.
Mer information om bifogade händelser i WPF finns i översikten över Bifogade händelser.
Kvalificerade händelsenamn i XAML
Syntaxen <owner type>.<event name>
kvalificerar ett händelsenamn med namnet på dess ägartyp. Med den här syntaxen kan en händelse kopplas till alla element, inte bara element som implementerar händelsen som medlem i deras klass. Syntaxen är tillämplig vid koppling av hanterare i XAML för bifogade händelser eller dirigerade händelser på godtyckliga element längs händelsevägen. Tänk på scenariot där du vill koppla en hanterare till ett överordnat element för att hantera dirigerade händelser som genereras på underordnade element. Om det överordnade elementet inte har den dirigerade händelsen som medlem måste du använda syntaxen för det kvalificerade händelsenamnet. Till exempel:
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
I exemplet är det föräldraelementets lyssnare som händelsehanteraren läggs till, en StackPanel. Men den Click dirigerade händelsen implementeras och aktiveras i klassen ButtonBase och är tillgänglig för klassen Button genom arv. Även om Button-klassen "äger" händelsen Click
tillåter det dirigerade händelsesystemet att hanterare för alla dirigerade händelser kopplas till alla UIElement eller ContentElement instanslyssnare som annars kan ha hanterare för en CLR-händelse. Standardnamnet xmlns
för dessa kvalificerade händelseattributnamn är vanligtvis wpf-standard xmlns
namnrymd, men du kan också ange prefixerade namnområden för anpassade dirigerade händelser. Mer information om xmlns
finns i XAML-namnområden och namnområdesmappning för WPF XAML-.
WPF-indatahändelser
En vanlig användning av routade händelser inom WPF-plattformen är för indatahändelser. Enligt konvention har routade händelser i WPF som följer en tunnelrutt namn som har prefixet "Preview". Prefixet Förhandsvisning innebär att förhandsgranskningshändelsen slutförs innan den kopplade bubbelhändelsen startar. Indatahändelser finns ofta i par, där den ena är en förhandsgranskningshändelse och den andra en bubblande dirigerad händelse. Till exempel PreviewKeyDown och KeyDown. Händelseparen delar samma instans av händelsedata, som för PreviewKeyDown
och KeyDown
är av typen KeyEventArgs. Ibland har indatahändelser bara en bubblande version, eller bara en direkt dirigerad version. I API-dokumentationen refererar routade händelseämnen till routade händelsepar och förtydligar routningsstrategin för varje dirigerad händelse.
WPF-inmatningshändelser som förekommer i par implementeras så att en enskild användaråtgärd från en inmatningsenhet, till exempel en knapptryckning med musen, genererar en förhandsgranskning och bubblande dirigerade händelser i följd. Först aktiveras förhandsgranskningshändelsen och dess väg slutförs. När förhandsgranskningsevenemanget har slutförts utlöses det bubblande evenemanget och fullföljer sin väg. Metodanropet RaiseEvent i implementeringsklassen som genererar den bubblande händelsen återanvänder händelsedata från förhandsgranskningshändelsen för den bubblande händelsen.
En förhandsgranskning av en inmatningshändelse som har markerats som hanterad kommer inte att anropa några normalt registrerade händelsehanterare för resten av förhandsgranskningsrutten, och den tillhörande bubbelhändelsen kommer inte att aktiveras. Det här hanteringsbeteendet är användbart för sammansatta kontrolldesigners som vill att träfftestbaserade indatahändelser eller fokusbaserade indatahändelser ska rapporteras på den översta nivån i deras kontroll. Element på den översta nivån i kontrollen har möjlighet att klasshantera förhandsgranskningshändelser från kontrollunderkomponenter för att "ersätta" dem med en kontrollspecifik händelse på den översta nivån.
För att illustrera hur bearbetning av indatahändelser fungerar bör du överväga följande exempel på indatahändelse. I följande trädbild är leaf element #2
källan till både de PreviewMouseDown
och MouseDown
kopplade händelserna:
Ordningen för händelsebearbetning efter en mus-ned-åtgärd på lövelement nr 2 är:
-
PreviewMouseDown
tunnelhändelse på rotelementet. -
PreviewMouseDown
tunnelhändelse på mellanliggande element nr 1. -
PreviewMouseDown
tunnelhändelse på lövelement nr 2, som är källelementet. -
MouseDown
bubblande händelse på lövelement nr 2, som är källelementet. -
MouseDown
bubblande händelse på mellanliggande element nr 1. -
MouseDown
bubblande händelse på rotelementet.
Den dirigerade händelsehanterardelegaten innehåller referenser till både det objekt som utlöste händelsen och objektet där hanteraren anropades. Objektet som ursprungligen skapade händelsen rapporteras av egenskapen Source i händelsedata. Objektet där hanteraren anropades rapporteras av parametern avsändare. För en viss routad händelseinstans ändras inte objektet som skapade händelsen när händelsen färdas genom elementträdet, men sender
gör det. I steg 3 och 4 i föregående diagram är Source
och sender
samma objekt.
Om din indatahändelsehanterare slutför den programspecifika logik som krävs för att hantera händelsen bör du markera indatahändelsen som hanterad. När en indatahändelse har markerats Handledanropas vanligtvis inte hanterare längre längs händelsevägen. Indatahändelsehanterare som är registrerade med parametern handledEventsToo
inställd på true
anropas dock även när händelsen markeras som hanterad. Mer information finns i Förhandsgranskning av händelser och Markera dirigerade händelser som hanterade, samt klasshantering.
Begreppet förhandsgranskning och bubblande händelsepar, med delade händelsedata och sekventiell höjning av förhandsgranskningshändelsen och den bubblande händelsen, gäller endast för vissa WPF-indatahändelser och inte för alla dirigerade händelser. Om du implementerar din egen indatahändelse för att hantera ett avancerat scenario bör du överväga att följa metoden med WPF-indatahändelsepar.
Om du implementerar din egen sammansatta kontroll som svarar på indatahändelser bör du överväga att använda förhandsgranskningshändelser för att undertrycka och ersätta indatahändelser som genererats på underkomponenter med en händelse på den översta nivån som representerar den fullständiga kontrollen. För mer information, se Märkning av dirigerade händelser som hanterade och hantering av klasser.
Mer information om WPF-indatasystemet och hur indata och händelser interagerar i vanliga programscenarier finns i Översikt över indata.
EventSetters och EventTriggers
I markeringsformat kan du inkludera fördefinierad XAML-händelsehanteringssyntax med hjälp av en EventSetter. När XAML bearbetas läggs den refererade hanteraren till i den formaterade instansen. Du kan bara deklarera ett EventSetter
för en routed event. I följande exempel implementeras den refererade ApplyButtonStyle
händelsehanterarmetoden i 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>
Det är troligt att noden Style
redan innehåller annan stilsinformation som gäller kontroller av den angivna typen, och att EventSetter är en del av dessa stilar främjar återanvändning av kod även på markeringsnivå. Dessutom abstraherar bort en EventSetter
metodnamn för hanterare från den allmänna applikationen och sidmarkeringen.
En annan specialiserad syntax som kombinerar funktionerna för dirigerad händelse och animering i WPF är en EventTrigger. Precis som med EventSetter
kan du bara deklarera en EventTrigger
för en dirigerad händelse. Vanligtvis deklareras en EventTrigger
som en del av ett format, men en EventTrigger
kan deklareras på sidnivåelement som en del av Triggers-samlingen eller i en ControlTemplate. Med en EventTrigger
kan du ange en Storyboard som körs när en dirigerad händelse når ett element i dess väg som deklarerar en EventTrigger
för händelsen. Fördelen med en EventTrigger
i jämförelse med att bara hantera händelsen och få den att starta en befintlig storyboard är att en EventTrigger
erbjuder bättre kontroll över storyboarden och dess beteende under körning. För mer information, se Använd händelseutlösare för att styra en storyboard efter att den har startat.
Mer om routade händelser
Du kan använda begreppen och vägledningen i den här artikeln som utgångspunkt när du skapar anpassade routade händelser i dina egna klasser. Du kan också stödja dina anpassade händelser med specialiserade händelsedataklasser och ombud. En routad händelseägare kan vara vilken klass som helst, men dirigerade händelser måste aktiveras av och hanteras av UIElement eller ContentElement härledda klasser för att vara användbara. Mer information om anpassade händelser finns i Skapa en anpassad dirigerad händelse.
Se även
.NET Desktop feedback