Panoramica degli eventi indirizzati (WPF .NET)
Gli sviluppatori di applicazioni e gli autori di componenti di Windows Presentation Foundation (WPF) possono usare gli eventi indirizzati per propagare gli eventi tramite un albero degli elementi e richiamare gestori eventi su più listener nell'albero. Queste funzionalità non vengono trovate negli eventi CLR (Common Language Runtime). Diversi eventi WPF sono eventi indirizzati, ad esempio ButtonBase.Click. Questo articolo illustra i concetti di base relativi agli eventi indirizzati e offre indicazioni su quando e come rispondere agli eventi indirizzati.
Prerequisiti
Questo articolo presuppone una conoscenza di base di Common Language Runtime (CLR), la programmazione orientata agli oggetti e il modo in cui il layout degli elementi WPF può essere concettualizzato come albero. Per seguire gli esempi in questo articolo, è utile se si ha familiarità con Extensible Application Markup Language (XAML) e si sa come scrivere applicazioni WPF.
Che cos'è un evento indirizzato?
È possibile prendere in considerazione gli eventi indirizzati dal punto di vista funzionale o di implementazione:
Dal punto di vista funzionale, un evento indirizzato è un tipo di evento che può richiamare gestori su più listener in un albero degli elementi, non solo nell'origine evento. Un listener di eventi è l'elemento in cui viene associato e richiamato un gestore eventi. Un'origine evento è l'elemento o l'oggetto che ha originariamente generato un evento.
Dal punto di vista dell'implementazione, un evento indirizzato è un evento registrato con il sistema di eventi WPF, supportato da un'istanza della RoutedEvent classe ed elaborato dal sistema di eventi WPF. In genere, un evento indirizzato viene implementato con un evento CLR "wrapper" per abilitare il collegamento di gestori in XAML e nel code-behind come si farebbe con un evento CLR.
Le applicazioni WPF in genere contengono molti elementi, dichiarati in XAML o di cui è stata creata un'istanza nel codice. Gli elementi di un'applicazione sono presenti all'interno dell'albero degli elementi. A seconda della modalità di definizione di un evento indirizzato, quando l'evento viene generato su un elemento di origine:
- Si scorrere l'albero degli elementi dall'elemento di origine all'elemento radice, che in genere è una pagina o una finestra.
- Esegue il tunneling verso il basso attraverso l'albero degli elementi dall'elemento radice all'elemento di origine.
- Non attraversa l'albero degli elementi e si verifica solo sull'elemento di origine.
Si consideri l'albero di elementi parziale seguente:
<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>
Viene eseguito il rendering dell'albero degli elementi come illustrato:
Ognuno dei tre pulsanti è una potenziale Click origine evento. Quando si fa clic su uno dei pulsanti, genera l'evento Click
che si apre dal pulsante all'elemento radice. Gli Button elementi e Border non dispongono di gestori eventi collegati, ma lo fa StackPanel . È possibile che altri elementi più in alto nell'albero non visualizzati abbiano Click
anche gestori eventi collegati. Quando l'evento raggiunge l'elemento Click
StackPanel
, il sistema di eventi WPF richiama il YesNoCancelButton_Click
gestore a cui è associato. La route di eventi per l'evento nell'esempio Click
è: Button
-StackPanel
> - ->Border
elementi> padre successivi.
Nota
L'elemento che originariamente ha generato un evento indirizzato viene identificato come nel RoutedEventArgs.Source parametro del gestore eventi. Il listener di eventi è l'elemento in cui il gestore eventi è associato e richiamato e viene identificato come mittente nei parametri del gestore eventi.
Scenari di primo livello per gli eventi indirizzati
Ecco alcuni degli scenari che motivano il concetto di evento indirizzato e lo distinguono da un tipico evento CLR:
Composizione e incapsulamento dei controlli: i vari controlli in WPF hanno una combinazione avanzata modalità tenda l. Ad esempio, è possibile inserire un'immagine all'interno di un Buttonoggetto , che estende in modo efficace la struttura ad albero visuale del pulsante. Tuttavia, l'immagine aggiunta non deve interrompere il comportamento di hit test del pulsante, che deve rispondere quando un utente fa clic sui pixel dell'immagine.
Punti di allegato del gestore singolare: puoi registrare un gestore per l'evento di
Click
ogni pulsante, ma con gli eventi indirizzati puoi collegare un singolo gestore come illustrato nell'esempio XAML precedente. In questo modo è possibile modificare l'albero degli elementi sotto il gestore singolare, ad esempio aggiungendo o rimuovendo più pulsanti, senza dover registrare l'evento diClick
ogni pulsante. Quando viene generato l'evento, laClick
logica del gestore può determinare da dove proviene l'evento. Il gestore seguente, specificato nell'albero degli elementi XAML illustrato in precedenza, contiene tale 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
Gestione delle classi: gli eventi indirizzati supportano un gestore eventi di classe definito in una classe. I gestori di classe gestiscono un evento prima di qualsiasi gestore di istanze per lo stesso evento in qualsiasi istanza della classe .
Riferimento a un evento senza reflection: ogni evento indirizzato crea un RoutedEvent identificatore di campo per fornire una tecnica di identificazione degli eventi affidabile che non richiede reflection statica o in fase di esecuzione per identificare l'evento.
Come vengono implementati gli eventi indirizzati
Un evento indirizzato è un evento registrato con il sistema di eventi WPF, supportato da un'istanza della RoutedEvent classe ed elaborato dal sistema eventi WPF. L'istanza RoutedEvent
, ottenuta dalla registrazione, viene in genere archiviata come public static readonly
membro della classe che l'ha registrata. Tale classe viene definita classe "owner" dell'evento. In genere, un evento indirizzato implementa un evento CLR denominato identico "wrapper". Il wrapper dell'evento CLR contiene add
e remove
funzioni di accesso per abilitare il collegamento di gestori in XAML e nel code-behind tramite la sintassi degli eventi specifica del linguaggio. Le add
funzioni di accesso e remove
e eseguono l'override dell'implementazione CLR e chiamano l'evento AddHandler e RemoveHandler i metodi indirizzati. Il meccanismo di backup e connessione degli eventi indirizzati è concettualmente simile al modo in cui una proprietà di dipendenza è una proprietà CLR supportata dalla DependencyProperty classe e registrata con il sistema di proprietà WPF.
L'esempio seguente registra l'evento Tap
indirizzato, archivia l'istanza restituita RoutedEvent
e implementa un wrapper di eventi CLR.
// 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
Strategie di routing
Gli eventi indirizzati usano una delle tre strategie di routing illustrate di seguito:
Bubbling: inizialmente vengono richiamati i gestori eventi nell'origine evento. L'evento indirizzato instrada quindi agli elementi padre successivi, richiamando i gestori eventi a sua volta, fino a raggiungere la radice dell'albero degli elementi. La maggior parte degli eventi indirizzati usa la strategia di bubbling. Gli eventi indirizzati di Bubbling vengono in genere usati per segnalare modifiche di input o stato da controlli compositi o altri elementi dell'interfaccia utente.
Tunneling: inizialmente vengono richiamati i gestori eventi alla radice dell'albero degli elementi. L'evento indirizzato instrada quindi agli elementi figlio successivi, richiamando i gestori eventi a sua volta, fino a raggiungere l'origine evento. Gli eventi che seguono una route di tunneling vengono definiti anche eventi di anteprima . Gli eventi di input WPF vengono in genere implementati come coppie di anteprima e di bubbling.
Diretto: vengono richiamati solo i gestori eventi nell'origine evento. Questa strategia non di routing è analoga agli eventi del framework dell'interfaccia utente di Windows Form, che sono eventi CLR standard. A differenza degli eventi CLR, gli eventi indirizzati diretti supportano la gestione delle classi e possono essere usati da EventSetters e EventTriggers.
Perché usare gli eventi indirizzati?
Gli sviluppatori di applicazioni non devono sempre sapere o tenere presente che l'evento che si sta gestendo viene implementato come evento indirizzato. Gli eventi indirizzati hanno un comportamento speciale, ma questo comportamento è in gran parte invisibile se si gestisce un evento sull'elemento che lo ha generato. Tuttavia, gli eventi indirizzati sono rilevanti quando si desidera associare un gestore eventi a un elemento padre per gestire gli eventi generati dagli elementi figlio, ad esempio all'interno di un controllo composito.
I listener di eventi indirizzati non necessitano degli eventi indirizzati gestiti come membri della classe. Qualsiasi UIElement oggetto o ContentElement può essere un listener di eventi per qualsiasi evento indirizzato. Poiché gli elementi visivi derivano da UIElement
o ContentElement
, è possibile usare gli eventi indirizzati come "interfaccia" concettuale che supporta lo scambio di informazioni sugli eventi tra elementi diversi in un'applicazione. Il concetto di "interfaccia" per gli eventi indirizzati è particolarmente applicabile agli eventi di input.
Gli eventi indirizzati supportano lo scambio di informazioni sugli eventi tra gli elementi lungo la route dell'evento perché ogni listener ha accesso alla stessa istanza dei dati dell'evento. Se un elemento cambia qualcosa nei dati dell'evento, tale modifica è visibile agli elementi successivi nella route dell'evento.
Oltre all'aspetto di routing, è possibile scegliere di implementare un evento indirizzato anziché un evento CLR standard per questi motivi:
Alcune funzionalità di applicazione di stili e modelli WPF, ad esempio EventSetters e EventTriggers, richiedono che l'evento di riferimento sia un evento indirizzato.
Gli eventi indirizzati supportano i gestori eventi della classe che gestiscono un evento prima di tutti i gestori di istanze per lo stesso evento in qualsiasi istanza della classe listener. Questa funzionalità è utile nella progettazione dei controlli perché il gestore classi può applicare comportamenti di classe basati su eventi che non possono essere eliminati accidentalmente da un gestore di istanze.
Collegare e implementare un gestore eventi indirizzato
In XAML associa un gestore eventi a un elemento dichiarando il nome dell'evento come attributo nell'elemento listener dell'evento. Il valore dell'attributo è il nome del metodo del gestore. Il metodo del gestore deve essere implementato nella classe parziale code-behind per la pagina XAML. Il listener di eventi è l'elemento in cui viene associato e richiamato il gestore eventi.
Per un evento che è un membro (ereditato o diverso) della classe listener, è possibile associare un gestore come indicato di seguito:
<Button Name="Button1" Click="Button_Click">Click me</Button>
Se l'evento non è un membro della classe del listener, è necessario usare il nome completo dell'evento sotto forma di <owner type>.<event name>
. Ad esempio, poiché la StackPanel classe non implementa l'evento Click , per associare un gestore a un per un StackPanel
Click
evento che si sposta fino a tale elemento, è necessario usare la sintassi del nome dell'evento qualificato:
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
La firma del metodo del gestore eventi nel code-behind deve corrispondere al tipo delegato per l'evento indirizzato. Il sender
parametro del RoutedEventHandler delegato per l'evento specifica l'elemento Click a cui è associato il gestore eventi. Il args
parametro del RoutedEventHandler
delegato contiene i dati dell'evento. Un'implementazione code-behind compatibile per il Button_Click
gestore eventi potrebbe essere:
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
Sebbene RoutedEventHandler sia il delegato del gestore eventi indirizzato di base, alcuni controlli o scenari di implementazione richiedono delegati diversi che supportano dati di eventi più specializzati. Ad esempio, per l'evento DragEnter indirizzato, il gestore deve implementare il DragEventHandler delegato. In questo modo, il codice del gestore può accedere alla DragEventArgs.Data proprietà nei dati dell'evento, che contiene il payload degli Appunti dall'operazione di trascinamento.
La sintassi XAML per l'aggiunta di gestori eventi indirizzati è identica a quella dei gestori eventi CLR standard. Per altre informazioni sull'aggiunta di gestori eventi in XAML, vedi XAML in WPF. Per un esempio completo di come associare un gestore eventi a un elemento usando XAML, vedi Come gestire un evento indirizzato.
Per associare un gestore eventi per un evento indirizzato a un elemento usando il codice, in genere sono disponibili due opzioni:
Chiamare direttamente il AddHandler metodo . I gestori eventi indirizzati possono essere sempre collegati in questo modo. Questo esempio associa un
Click
gestore eventi a un pulsante usando ilAddHandler
metodo :Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
Per associare un gestore per l'evento del
Click
pulsante a un elemento diverso nella route dell'evento, ad esempio un StackPanel oggetto denominatoStackPanel1
:StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
Se l'evento indirizzato implementa un wrapper di eventi CLR, usare la sintassi di eventi specifica del linguaggio per aggiungere gestori eventi esattamente come si farebbe per un evento CLR standard. La maggior parte degli eventi indirizzati WPF esistenti implementa il wrapper CLR, abilitando così la sintassi degli eventi specifica del linguaggio. Questo esempio associa un
Click
gestore eventi a un pulsante usando la sintassi specifica del linguaggio:Button1.Click += Button_Click;
AddHandler Button1.Click, AddressOf Button_Click
Per un esempio di come collegare un gestore eventi nel codice, vedere Come aggiungere un gestore eventi usando il codice. Se si sta codificando in Visual Basic, è anche possibile usare la Handles
parola chiave per aggiungere gestori come parte delle dichiarazioni del gestore. Per altre informazioni, vedere Gestione degli eventi di Visual Basic e WPF.
Il concetto di gestito
Tutti gli eventi indirizzati condividono una classe base comune per i dati dell'evento, ovvero la RoutedEventArgs classe . La RoutedEventArgs
classe definisce la proprietà booleana Handled . Lo scopo della Handled
proprietà è consentire a qualsiasi gestore eventi lungo la route dell'evento di contrassegnare l'evento indirizzato come gestito. Per contrassegnare un evento come gestito, impostare il valore di Handled
su true
nel codice del gestore eventi.
Il valore di influisce sulla modalità di elaborazione di Handled
un evento indirizzato durante il percorso dell'evento. Se Handled
si trova true
nei dati dell'evento condiviso di un evento indirizzato, i gestori collegati ad altri elementi lungo la route dell'evento in genere non verranno richiamati per tale istanza di evento specifica. Per gli scenari più comuni del gestore, contrassegnare un evento come gestito arresta efficacemente i gestori successivi lungo la route dell'evento, indipendentemente dal fatto che i gestori dell'istanza o della classe rispondano a tale istanza di evento specifica. Tuttavia, in rari casi in cui è necessario il gestore eventi per rispondere agli eventi indirizzati contrassegnati come gestiti, è possibile:
Collegare il gestore nel code-behind usando l'overload AddHandler(RoutedEvent, Delegate, Boolean) , con il
handledEventsToo
parametro impostato sutrue
.Impostare l'attributo HandledEventsToo in un
EventSetter
oggetto sutrue
.
Il concetto di potrebbe influire sulla progettazione dell'applicazione Handled
e del codice dei gestori eventi. È possibile concettualizzare Handled
come un semplice protocollo per l'elaborazione di eventi indirizzati. Come si usa questo protocollo è possibile, ma l'uso previsto del Handled
parametro è:
Se un evento indirizzato viene contrassegnato come gestito, non deve essere gestito di nuovo da altri elementi lungo la route.
Se un evento indirizzato non viene contrassegnato come gestito, i listener precedenti nella route dell'evento non hanno un gestore per l'evento o nessuno dei gestori registrati ha risposto all'evento in modo da contrassegnare l'evento come gestito. I gestori del listener corrente hanno tre possibili corsi di azione:
Non intervenire affatto. L'evento rimane non gestito e instrada il listener successivo nell'albero.
Eseguire il codice in risposta all'evento, ma non in una misura che giustifica il contrassegno dell'evento come gestito. L'evento rimane non gestito e instrada il listener successivo nell'albero.
Eseguire il codice in risposta all'evento, in modo da poter contrassegnare l'evento come gestito. Contrassegnare l'evento come gestito nei dati dell'evento. L'evento viene comunque instradato al listener successivo nell'albero, ma la maggior parte dei listener non richiama altri gestori. L'eccezione è costituito dai listener con gestori registrati specificamente con
handledEventsToo
impostato sutrue
.
Per altre informazioni sulla gestione degli eventi indirizzati, vedere Contrassegnare gli eventi indirizzati come gestiti e la gestione delle classi.
Anche se gli sviluppatori che gestiscono solo un evento indirizzato bubbling sull'oggetto che lo ha generato potrebbe non essere interessato ad altri listener, è consigliabile contrassegnare l'evento come gestito comunque. In questo modo si evitano effetti collaterali imprevisti se un elemento lungo la route dell'evento ha un gestore per lo stesso evento indirizzato.
Gestori di classi
I gestori eventi indirizzati possono essere gestori di istanze o gestori di classi. I gestori di classe per una determinata classe vengono richiamati prima che qualsiasi gestore dell'istanza risponda allo stesso evento in qualsiasi istanza di tale classe. A causa di questo comportamento, quando gli eventi indirizzati vengono contrassegnati come gestiti, vengono spesso contrassegnati come tali all'interno dei gestori di classe. Esistono due tipi di gestori di classi:
- Gestori eventi di classe statici, registrati chiamando il RegisterClassHandler metodo all'interno di un costruttore di classi statiche.
- Eseguire l'override dei gestori eventi della classe, registrati eseguendo l'override dei metodi di evento virtuali della classe base. I metodi di evento virtuali della classe base esistono principalmente per gli eventi di input e hanno nomi che iniziano con Il nome dell'evento On e il<nome>> dell'evento OnPreview.<
Alcuni controlli WPF hanno una gestione intrinseca della classe per determinati eventi indirizzati. La gestione delle classi potrebbe dare l'aspetto esterno che l'evento indirizzato non viene mai generato, ma in realtà viene contrassegnato come gestito da un gestore di classi. Se è necessario che il gestore eventi risponda all'evento gestito, è possibile registrare il gestore con handledEventsToo
impostato su true
. Per altre informazioni, sia sull'implementazione di gestori di classi personalizzati che sulla gestione delle classi indesiderate, vedere Contrassegnare gli eventi indirizzati come gestiti e la gestione delle classi.
Eventi associati in WPF
Il linguaggio XAML definisce anche un tipo speciale di evento denominato evento associato. Gli eventi associati possono essere usati per definire un nuovo evento indirizzato in una classe non elemento e generare tale evento su qualsiasi elemento dell'albero. A tale scopo, è necessario registrare l'evento associato come evento indirizzato e fornire codice di supporto specifico che supporta la funzionalità di evento associata. Poiché gli eventi associati vengono registrati come eventi indirizzati, quando generati su un elemento vengono propagati attraverso l'albero degli elementi.
Nella sintassi XAML, un evento associato viene specificato dal nome dell'evento e dal tipo di proprietario, sotto forma di <owner type>.<event name>
. Poiché il nome dell'evento è qualificato con il nome del tipo di proprietario, la sintassi consente di associare l'evento a qualsiasi elemento di cui è possibile creare un'istanza. Questa sintassi è applicabile anche ai gestori per gli eventi indirizzati regolari che si collegano a un elemento arbitrario lungo la route dell'evento. È anche possibile collegare gestori per gli eventi associati nel code-behind chiamando il AddHandler metodo sull'oggetto a cui deve essere associato il gestore.
Il sistema di input WPF usa ampiamente gli eventi associati. Tuttavia, quasi tutti gli eventi associati vengono visualizzati come eventi indirizzati non associati equivalenti tramite elementi di base. Raramente si useranno o si gestiranno direttamente gli eventi associati. Ad esempio, è più facile gestire l'evento associato Mouse.MouseDown sottostante su un UIElement tramite l'evento indirizzato equivalente UIElement.MouseDown rispetto all'uso della sintassi di eventi associata in XAML o code-behind.
Per altre informazioni sugli eventi associati in WPF, vedere Panoramica degli eventi associati.
Nomi di eventi qualificati in XAML
La <owner type>.<event name>
sintassi qualifica un nome di evento con il nome del tipo di proprietario. Questa sintassi consente di associare un evento a qualsiasi elemento, non solo agli elementi che implementano l'evento come membro della relativa classe. La sintassi è applicabile quando si collegano gestori in XAML per gli eventi associati o gli eventi indirizzati su elementi arbitrari lungo la route dell'evento. Si consideri lo scenario in cui si vuole associare un gestore a un elemento padre per gestire gli eventi indirizzati generati sugli elementi figlio. Se l'elemento padre non ha l'evento indirizzato come membro, è necessario usare la sintassi del nome dell'evento qualificato. Ad esempio:
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
Nell'esempio il listener dell'elemento padre a cui viene aggiunto il gestore eventi è .StackPanel Tuttavia, l'evento Click indirizzato viene implementato e generato nella ButtonBase classe e disponibile per la Button classe tramite ereditarietà. Anche se la Button classe è proprietaria dell'evento Click
, il sistema di eventi indirizzato consente ai gestori di qualsiasi evento indirizzato di essere collegato a qualsiasi UIElement listener dell'istanza o ContentElement che potrebbe altrimenti avere gestori per un evento CLR. Lo spazio dei nomi predefinito xmlns
per questi nomi di attributi di evento qualificati è in genere lo spazio dei nomi WPF xmlns
predefinito, ma è anche possibile specificare spazi dei nomi con prefisso per gli eventi indirizzati personalizzati. Per altre informazioni su xmlns
, vedere Spazi dei nomi XAML e mapping degli spazi dei nomi per XAML WPF.
Eventi di input WPF
Un'applicazione frequente di eventi indirizzati all'interno della piattaforma WPF è destinata agli eventi di input. Per convenzione, gli eventi indirizzati WPF che seguono una route di tunneling hanno un nome preceduto da "Anteprima". Il prefisso Preview indica che l'evento di anteprima viene completato prima dell'avvio dell'evento di bubbling associato. Gli eventi di input vengono spesso visualizzati in coppia, con un evento di anteprima e l'altro un evento indirizzato bubbling. Ad esempio, PreviewKeyDown e KeyDown. Le coppie di eventi condividono la stessa istanza dei dati dell'evento, che per PreviewKeyDown
e KeyDown
è di tipo KeyEventArgs. In alcuni casi, gli eventi di input hanno solo una versione di bubbling o solo una versione indirizzata diretta. Nella documentazione dell'API, gli argomenti relativi agli eventi indirizzati con riferimenti incrociati e chiarire la strategia di routing per ogni evento indirizzato.
Gli eventi di input WPF che arrivano in coppie vengono implementati in modo che una singola azione dell'utente da un dispositivo di input, ad esempio una pressione del pulsante del mouse, generi l'anteprima e gli eventi indirizzati in sequenza. Prima di tutto, viene generato l'evento di anteprima e ne completa la route. Al termine dell'evento di anteprima, viene generato l'evento di bubbling e ne completa la route. La RaiseEvent chiamata al metodo nella classe di implementazione che genera l'evento di bubbling riutilizza i dati dell'evento di anteprima per l'evento di bubbling.
Un evento di input di anteprima contrassegnato come gestito non richiama i gestori eventi normalmente registrati per il resto della route di anteprima e l'evento di bubbling associato non verrà generato. Questo comportamento di gestione è utile per i progettisti di controlli compositi che desiderano che gli eventi di input basati su hit test o gli eventi di input basati sullo stato attivo vengano segnalati al livello superiore del controllo. Gli elementi di primo livello del controllo hanno la possibilità di gestire gli eventi di anteprima di classe dai sottocomponenti del controllo per "sostituirli" con un evento specifico del controllo di primo livello.
Per illustrare il funzionamento dell'elaborazione degli eventi di input, considerare l'esempio di evento di input seguente. Nell'illustrazione dell'albero seguente è leaf element #2
l'origine degli PreviewMouseDown
eventi associati e MouseDown
:
L'ordine di elaborazione degli eventi dopo un'azione di scorrimento del mouse sull'elemento foglia n. 2 è:
PreviewMouseDown
evento di tunneling sull'elemento radice.PreviewMouseDown
evento di tunneling sull'elemento intermedio n. 1.PreviewMouseDown
evento di tunneling sull'elemento foglia n. 2, ovvero l'elemento di origine.MouseDown
evento bubbling nell'elemento foglia n. 2, ovvero l'elemento di origine.MouseDown
evento di bubbling nell'elemento intermedio n. 1.MouseDown
evento di bubbling nell'elemento radice.
Il delegato del gestore eventi indirizzato fornisce riferimenti sia all'oggetto che ha generato l'evento che all'oggetto in cui è stato richiamato il gestore. L'oggetto che ha originariamente generato l'evento viene segnalato dalla Source proprietà nei dati dell'evento. L'oggetto in cui il gestore è stato richiamato viene segnalato dal parametro sender . Per qualsiasi istanza dell'evento indirizzato specificata, l'oggetto che ha generato l'evento non cambia man mano che l'evento passa attraverso l'albero degli elementi, ma lo sender
fa. Nei passaggi 3 e 4 del diagramma precedente, Source
e sender
sono lo stesso oggetto .
Se il gestore eventi di input completa la logica specifica dell'applicazione necessaria per risolvere l'evento, è necessario contrassegnare l'evento di input come gestito. In genere, una volta contrassegnato Handledun evento di input, i gestori lungo la route dell'evento non vengono richiamati. Tuttavia, i gestori eventi di input registrati con il handledEventsToo
parametro impostato su true
verranno richiamati anche quando l'evento viene contrassegnato come gestito. Per altre informazioni, vedere Eventi di anteprima e Contrassegno degli eventi indirizzati come gestiti e gestione delle classi.
Il concetto di coppie di eventi di anteprima e di bubbling, con dati di evento condivisi e generazione sequenziale dell'evento di anteprima, quindi l'evento di bubbling si applica solo ad alcuni eventi di input WPF e non a tutti gli eventi indirizzati. Se si implementa un evento di input personalizzato per risolvere uno scenario avanzato, prendere in considerazione l'approccio alla coppia di eventi di input WPF.
Se si implementa un controllo composito personalizzato che risponde agli eventi di input, è consigliabile usare gli eventi di anteprima per eliminare e sostituire gli eventi di input generati nei sottocomponenti con un evento di primo livello che rappresenta il controllo completo. Per altre informazioni, vedere Contrassegnare gli eventi indirizzati come gestiti e la gestione delle classi.
Per altre informazioni sul sistema di input WPF e sul modo in cui gli input e gli eventi interagiscono in scenari di applicazioni tipici, vedere Panoramica dell'input.
EventSetters ed EventTriggers
Negli stili di markup puoi includere la sintassi di gestione degli eventi XAML pre-dichiarata usando un oggetto EventSetter. Quando il codice XAML viene elaborato, il gestore a cui viene fatto riferimento viene aggiunto all'istanza di stile. È possibile dichiarare un oggetto EventSetter
solo per un evento indirizzato. Nell'esempio seguente il metodo del gestore eventi di ApplyButtonStyle
riferimento viene implementato nel 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>
È probabile che il nodo contenga già altre informazioni di stile relative ai controlli del tipo specificato e che l'uso EventSetter di tali stili favorisce il Style
riutilizzo del codice anche a livello di markup. Inoltre, un EventSetter
metodo astrae i nomi per i gestori lontano dall'applicazione generale e dal markup di pagina.
Un'altra sintassi specializzata che combina l'evento indirizzato e le funzionalità di animazione di WPF è un oggetto EventTrigger. Come per EventSetter
, è possibile dichiarare solo un EventTrigger
oggetto per un evento indirizzato. In genere, un oggetto EventTrigger
viene dichiarato come parte di uno stile, ma può EventTrigger
essere dichiarato negli elementi a livello di pagina come parte della Triggers raccolta o in un oggetto ControlTemplate. Un EventTrigger
oggetto consente di specificare un Storyboard oggetto che viene eseguito ogni volta che un evento indirizzato raggiunge un elemento nella route che dichiara un oggetto EventTrigger
per tale evento. Il vantaggio di un EventTrigger
oggetto rispetto alla semplice gestione dell'evento e alla sua avvio di uno storyboard esistente è che offre un EventTrigger
controllo migliore sullo storyboard e sul relativo comportamento di run-time. Per altre informazioni, vedere Usare trigger di eventi per controllare uno storyboard dopo l'avvio.
Altre informazioni sugli eventi indirizzati
È possibile usare i concetti e le linee guida in questo articolo come punto di partenza per la creazione di eventi indirizzati personalizzati nelle proprie classi. È anche possibile supportare gli eventi personalizzati con classi di dati e delegati di eventi specializzati. Un proprietario dell'evento indirizzato può essere qualsiasi classe, ma gli eventi indirizzati devono essere generati e gestiti da UIElement o ContentElement classi derivate per essere utili. Per altre informazioni sugli eventi personalizzati, vedere Creare un evento indirizzato personalizzato.
Vedi anche
.NET Desktop feedback