Cenni preliminari sugli eventi indirizzati

Questo argomento descrive il concetto di eventi indirizzati in Windows Presentation Foundation (WPF). L'argomento definisce la terminologia correlata agli eventi indirizzati, descrive in che modo questi eventi sono indirizzati lungo un albero di elementi, riepiloga le modalità di gestione degli eventi indirizzati e spiega come creare eventi indirizzati personalizzati.

Prerequisiti

In questo argomento si presuppone che si abbia una conoscenza di base di Common Language Runtime (CLR) e della programmazione orientata agli oggetti, nonché il concetto di come le relazioni tra elementi WPF possono essere concettualizzate come albero. Per seguire gli esempi in questo argomento, è necessario comprendere anche Extensible Application Markup Language (XAML) e sapere come scrivere pagine o applicazioni WPF di base. Per altre informazioni, vedere Procedura dettagliata: Prima applicazione desktop WPF e XAML in WPF.

Definizione di evento indirizzato

È possibile considerare gli eventi indirizzati da un punto di vista funzionale o da una prospettiva di implementazione. In questo argomento sono illustrati entrambi i concetti, perché alcuni utenti trovano più utile il primo e altri il secondo.

Definizione funzionale: un evento indirizzato è un tipo di evento che può richiamare gestori su più listener in un albero degli elementi invece che solo sull'oggetto che ha generato l'evento.

Definizione di implementazione: un evento indirizzato è un evento CLR supportato da un'istanza della RoutedEvent classe ed elaborato dal sistema di eventi Windows Presentation Foundation (WPF).

Un'applicazione WPF tipica contiene molti elementi. Indipendentemente dal fatto che sia stato creato nel codice o dichiarato in XAML, questi elementi esistono in una relazione di albero degli elementi tra loro. La route dell'evento può procedere in una di due direzioni, in base alla definizione dell'evento, ma generalmente parte dall'elemento di origine e sale (bubbling) lungo l'albero degli elementi fino a raggiunge la radice dell'albero (in genere una pagina o una finestra). Questo concetto di bubbling può risultare familiare a chi in precedenza ha già usato il modello a oggetti DHTML.

Considerare il semplice albero degli elementi seguente:

<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>

Questo albero degli elementi produce un risultato analogo al seguente:

Yes, No, and Cancel buttons

In questa struttura ad albero degli elementi semplificata, l'origine di un Click evento è uno degli Button elementi e a qualsiasi Button elemento selezionato è il primo elemento che ha la possibilità di gestire l'evento. Ma se nessun gestore associato agli Button atti sull'evento, l'evento passerà verso l'alto verso l'alto all'elemento Button padre nell'albero degli elementi, ovvero .StackPanel Potenzialmente, l'evento passa a Bordere quindi oltre alla radice della pagina dell'albero degli elementi (non visualizzato).

In altre parole, la route di eventi per questo Click evento è:

Button-->StackPanel-->Border-->...

Scenari principali per gli eventi indirizzati

Di seguito è riportato un breve riepilogo degli scenari che hanno motivato il concetto di evento indirizzato e il motivo per cui un tipico evento CLR non era adeguato per questi scenari:

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 testing che fa sì che un pulsante risponda a un Click del relativo contenuto, anche se l'utente fa clic sui pixel che fanno tecnicamente parte dell'immagine.

Singoli punti di collegamento del gestore: in Windows Form, è necessario associare lo stesso gestore più volte per elaborare eventi che possono essere generati da più elementi. Gli eventi indirizzati consentono di associare il gestore una sola volta, come illustrato nell'esempio precedente, e di usare la logica del gestore per determinare da dove proviene l'evento, se necessario. Ad esempio, questo potrebbe essere il gestore per il codice XAML illustrato in precedenza:

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

Gestione delle classi: gli eventi indirizzati consentono un gestore statico definito dalla classe. Questo gestore di classi ha la possibilità di gestire un evento prima di qualsiasi gestore di istanze associato.

Riferimento a un evento senza reflection: alcune tecniche di codice e di markup richiedono un modo per identificare un evento specifico. Un evento indirizzato crea un RoutedEvent campo come identificatore, che fornisce una tecnica affidabile di identificazione degli eventi che non richiede reflection statica o in fase di esecuzione.

Modalità di implementazione degli eventi indirizzati

Un evento indirizzato è un evento CLR supportato da un'istanza della RoutedEvent classe e registrato con il sistema di eventi WPF. L'istanza RoutedEvent ottenuta dalla registrazione viene in genere mantenuta come publicstaticreadonly membro di campo della classe che registra e di conseguenza "possiede" l'evento indirizzato. La connessione all'evento CLR denominato in modo identico (talvolta definito evento "wrapper") viene eseguita eseguendo l'override delle add implementazioni e remove per l'evento CLR. Normalmente, add e remove vengono lasciati come impostazione predefinita implicita che usa la sintassi di evento specifica del linguaggio per aggiungere e rimuovere i gestori dell'evento. Il meccanismo di backing 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.

Nell'esempio seguente viene illustrata la dichiarazione per un evento indirizzato personalizzato Tap , inclusa la registrazione e l'esposizione del RoutedEvent campo dell'identificatore e delle add implementazioni e remove per l'evento Tap CLR.

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

Gestori di eventi indirizzati e XAML

Per aggiungere un gestore per un evento usando XAML, dichiari il nome dell'evento come attributo sull'elemento che è un listener di eventi. Il valore dell'attributo è il nome del metodo del gestore implementato, che deve trovarsi nella classe parziale del file code-behind.

<Button Click="b1SetColor">button</Button>

La sintassi XAML per l'aggiunta di gestori eventi CLR standard è la stessa per l'aggiunta di gestori eventi indirizzati, perché si aggiungono effettivamente gestori al wrapper dell'evento CLR, che ha un'implementazione di eventi indirizzata sottostante. Per altre informazioni sull'aggiunta di gestori eventi in XAML, vedi XAML in WPF.

Strategie di routing

Gli eventi indirizzati usano una delle tre strategie di routing illustrate di seguito:

  • Bubbling: vengono richiamati i gestori eventi sull'origine dell'evento. L'evento indirizzato viene quindi indirizzato agli elementi padre successivi 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 l'input o le modifiche dello stato da controlli distinti o altri elementi dell'interfaccia utente.

  • Diretto: solo l'elemento di origine può richiamare i gestori in risposta. Questo è analogo al "routing" usato Windows Form per gli eventi. Tuttavia, a differenza di un evento CLR standard, gli eventi indirizzati diretti supportano la gestione delle classi (la gestione delle classi è illustrata in una sezione futura) e possono essere usati da EventSetter e EventTrigger.

  • Tunneling: inizialmente vengono richiamati i gestori eventi alla radice dell'albero degli elementi. L'evento indirizzato percorre quindi una route attraverso elementi figlio successivi, verso l'elemento nodo che rappresenta l'origine dell'evento indirizzato (l'elemento che ha generato l'evento indirizzato). Gli eventi indirizzati di tunneling vengono spesso usati o gestiti come parte della composizione di un controllo, in modo che gli eventi di parti composite possano essere deliberatamente eliminati o sostituiti da eventi specifici del controllo completo. Gli eventi di input forniti in WPF vengono spesso implementati come coppia di tunneling/bubbling. Gli eventi di tunneling sono talvolta anche detti eventi di anteprima, per una convenzione di denominazione usata per le coppie.

Vantaggi offerti dall'uso degli eventi indirizzati

Per gli sviluppatori di applicazioni non è sempre necessario o importante sapere se l'evento gestito è implementato come evento indirizzato. Gli eventi indirizzati hanno un comportamento speciale, che però è per lo più invisibile se l'evento viene gestito sull'elemento in cui è stato generato.

Gli eventi indirizzati diventano particolarmente efficaci se si usa uno degli scenari suggeriti: definizione di gestori comuni in una radice comune, composizione di un controllo personalizzato o definizione di una classe di controlli personalizzata.

Non è necessario che i listener e le origini degli eventi indirizzati condividano un evento comune nella gerarchia. Qualsiasi UIElement oggetto o ContentElement può essere un listener di eventi per qualsiasi evento indirizzato. Pertanto, è possibile usare il set completo di eventi indirizzati disponibili in tutto il set di API di lavoro come "interfaccia" concettuale, in cui elementi diversi nell'applicazione possono scambiare informazioni sugli eventi. Questo concetto di "interfaccia" per gli eventi indirizzati è applicabile in particolar modo agli eventi di input.

Gli eventi indirizzati possono anche essere usati per comunicare nell'albero degli elementi, poiché i dati di un evento vengono trasmessi a ogni elemento nella route. Se un elemento modifica in qualche modo i dati dell'evento, tale modifica risulta disponibile per l'elemento successivo nella route.

Oltre all'aspetto di routing, esistono due altri motivi per cui qualsiasi evento WPF specificato potrebbe essere implementato come evento indirizzato anziché come evento CLR standard. Se si implementano eventi personalizzati, considerare anche questi principi:

  • Alcune funzionalità di applicazione di stili e modelli WPF, ad EventSetter esempio e EventTrigger richiedono che l'evento a cui si fa riferimento sia un evento indirizzato. Si tratta dello scenario di identificatore dell'evento citato in precedenza.

  • Gli eventi indirizzati supportano un meccanismo di gestione delle classi in base al quale la classe può specificare metodi statici che hanno la possibilità di gestire gli eventi indirizzati prima che qualsiasi gestore di istanze registrato possa accedervi. Questa funzionalità è molto utile nella progettazione di controlli, perché la classe può imporre comportamenti di classe basati su eventi che non possono essere eliminati accidentalmente mediante la gestione di un evento su un'istanza.

Ognuna delle considerazioni precedenti viene discussa in una sezione separata di questo argomento.

Aggiunta e implementazione di un gestore eventi per un evento indirizzato

Per aggiungere un gestore eventi in XAML, è sufficiente aggiungere il nome dell'evento a un elemento come attributo e impostare il valore dell'attributo come nome del gestore eventi che implementa un delegato appropriato, come nell'esempio seguente.

<Button Click="b1SetColor">button</Button>

b1SetColor è il nome del gestore implementato che contiene il codice che gestisce l'evento Click . b1SetColor deve avere la stessa firma del RoutedEventHandler delegato, ovvero il delegato del gestore eventi per l'evento Click . Il primo parametro di tutti i delegati dei gestori di eventi indirizzati specifica l'elemento a cui viene aggiunto il gestore eventi, mentre il secondo parametro specifica i dati per l'evento.

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 è il delegato del gestore eventi indirizzato di base. Per gli eventi indirizzati specializzati per determinati controlli o scenari, i delegati da usare per i gestori di eventi indirizzati possono anche essere più specializzati, in modo da poter trasmettere dati di eventi specializzati. Ad esempio, in uno scenario di input comune, è possibile gestire un DragEnter evento indirizzato. Il gestore deve implementare il DragEventHandler delegato. Usando il delegato più specifico, è possibile elaborare DragEventArgs nel gestore e leggere la Data proprietà , che contiene il payload degli Appunti dell'operazione di trascinamento.

Per un esempio completo di come aggiungere un gestore eventi a un elemento usando XAML, vedi Gestire un evento indirizzato.

L'aggiunta di un gestore per un evento indirizzato in un'applicazione creata nel codice è semplice. I gestori eventi indirizzati possono sempre essere aggiunti tramite un metodo AddHandler helper (che è lo stesso metodo che le chiamate di supporto esistenti per add.) Tuttavia, gli eventi indirizzati WPF esistenti hanno in genere implementazioni di supporto di add e remove logica che consentono ai gestori per gli eventi indirizzati di essere aggiunti da una sintassi di eventi specifica del linguaggio, che è più intuitiva della sintassi helper. Di seguito è illustrato un esempio di utilizzo del metodo helper:

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

L'esempio seguente mostra la sintassi dell'operatore C#(Visual Basic ha una sintassi di operatore leggermente diversa a causa della gestione della dereferenziazione):

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

Per un esempio di come aggiungere un gestore eventi nel codice, vedere Aggiungere un gestore eventi mediante codice.

Se si usa Visual Basic, è anche possibile usare la Handles parola chiave per aggiungere gestori come parte delle dichiarazioni del gestore. Per altre informazioni, vedere Visual Basic e la gestione degli eventi WPF.

Concetto di gestito

Tutti gli eventi indirizzati condividono una classe di base di dati di eventi comune, RoutedEventArgs. RoutedEventArgs definisce la Handled proprietà , che accetta un valore booleano. Lo scopo della Handled proprietà è consentire a qualsiasi gestore eventi lungo la route di contrassegnare l'evento indirizzato come gestito, impostando il valore di Handled su true. Dopo essere stati elaborati dal gestore in corrispondenza di un elemento lungo la route, i dati di evento condivisi vengono nuovamente segnalati a ogni listener lungo la route.

Il valore di influisce sulla modalità di segnalazione o elaborazione di Handled un evento indirizzato durante il viaggio lungo il percorso. Se Handled si trova true nei dati dell'evento per un evento indirizzato, i gestori che restano in ascolto di tale evento indirizzato su altri elementi non vengono in genere richiamati per tale istanza dell'evento specifico. Questo vale sia per i gestori collegati in XAML che per i gestori aggiunti da sintassi degli allegati del gestore eventi specifici del linguaggio, += ad esempio o Handles. Per gli scenari di gestori più comuni, contrassegnare un evento come gestito impostando Handled su true interromperà il routing per una route di tunneling o una route di bubbling e anche per qualsiasi evento gestito in un punto della route da un gestore di classi.

Esiste tuttavia un meccanismo "handledEventsToo" in cui i listener possono comunque eseguire gestori in risposta agli eventi indirizzati in cui Handled si trovano true i dati dell'evento. In altre parole, la route dell'evento non viene effettivamente interrotta contrassegnando i dati di evento come gestiti. È possibile usare solo il meccanismo handledEventsToo nel codice o in :EventSetter

Oltre al comportamento prodotto Handled in eventi indirizzati, il concetto di Handled ha implicazioni per la progettazione dell'applicazione e la scrittura del codice del gestore eventi. È possibile concettualizzare Handled come un protocollo semplice esposto da eventi indirizzati. Esattamente come si usa questo protocollo, ma la progettazione concettuale per la modalità di utilizzo del valore di Handled è la seguente:

  • Se un evento indirizzato è contrassegnato come gestito, non è necessario che venga gestito nuovamente da altri elementi lungo la route.

  • Se un evento indirizzato non è contrassegnato come gestito, altri listener che erano in precedenza lungo la route hanno scelto di non registrare un gestore o i gestori registrati hanno scelto di non modificare i dati dell'evento e impostare su Handledtrue. In alternativa, è ovviamente possibile che il listener corrente sia il primo punto della route. I gestori del listener corrente hanno ora tre possibili corsi di azione:

    • Non eseguire alcuna azione. L'evento rimane non gestito e viene indirizzato al listener successivo.

    • Eseguire il codice in risposta all'evento, ma stabilire che l'azione eseguita non è sufficiente per contrassegnare l'evento come gestito. L'evento viene indirizzato al listener successivo.

    • Eseguire il codice in risposta all'evento. Contrassegnare l'evento come gestito nei dati di evento passati al gestore, perché l'azione eseguita viene ritenuta sufficiente per contrassegnare l'evento come gestito. L'evento viene comunque instradato al listener successivo, ma con Handled=true nei dati dell'evento, quindi solo i handledEventsToo listener hanno la possibilità di richiamare altri gestori.

Questa progettazione concettuale è rafforzata dal comportamento di routing indicato in precedenza: è più difficile (anche se ancora possibile nel codice o negli stili) collegare gestori per gli eventi indirizzati richiamati anche se un gestore precedente lungo la route è già impostato su Handledtrue.

Per altre informazioni su , la Handledgestione delle classi degli eventi indirizzati e le raccomandazioni su quando è appropriato contrassegnare un evento indirizzato come Handled, vedere Contrassegnare gli eventi indirizzati come gestiti e gestione delle classi.

Nelle applicazioni, è piuttosto comune gestire un evento indirizzato di bubbling solo sull'oggetto che lo ha generato, senza preoccuparsi delle caratteristiche di routing dell'evento. È tuttavia comunque consigliabile contrassegnare l'evento indirizzato come gestito nei dati di evento, per evitare effetti collaterali imprevisti nel caso in cui un elemento più in alto nell'albero degli elementi abbia un gestore associato per lo stesso evento indirizzato.

Gestori di classi

Se si definisce una classe che deriva in qualche modo da DependencyObject, è anche possibile definire e associare un gestore di classi per un evento indirizzato che è un membro di evento dichiarato o ereditato della classe. I gestori di classi vengono richiamati prima dei gestori di listener di istanze associati a un'istanza di tale classe, ogni volta che un evento indirizzato raggiunge un'istanza dell'elemento nella relativa route.

Alcuni controlli WPF hanno una gestione intrinseca della classe per determinati eventi indirizzati. In questo modo potrebbe sembrare che l'evento indirizzato non venga mai generato, ma in realtà viene gestito tramite classi e, usando determinate tecniche, può essere ancora gestito dai gestori di istanze. Molti controlli e classi di base, inoltre, espongono metodi virtuali che possono essere usati per eseguire l'override del comportamento di gestione delle classi. Per altre informazioni su come evitare un comportamento di gestione delle classi non desiderato e su come definire la gestione delle classi in una classe personalizzata, vedere Contrassegno degli eventi indirizzati come gestiti e gestione delle classi.

Eventi associati in WPF

Il linguaggio XAML definisce anche un tipo speciale di evento denominato evento associato. Un evento associato consente di aggiungere un gestore per un determinato evento a un elemento arbitrario. L'elemento che gestisce l'evento non deve necessariamente definire o ereditare l'evento associato, né l'oggetto che genera potenzialmente l'evento o l'istanza di gestione di destinazione deve necessariamente definire o "possedere" in altro modo tale evento come membro della classe.

Il sistema di input WPF usa ampiamente gli eventi associati. Tuttavia, quasi tutti questi eventi associati vengono inoltrati tramite elementi di base. Gli eventi di input appaiono quindi come eventi indirizzati non associati equivalenti, membri della classe di elementi di base. Ad esempio, l'evento Mouse.MouseDown associato sottostante può essere gestito più facilmente in qualsiasi dato UIElement usando MouseDown in tale UIElement elemento anziché gestire la sintassi degli eventi associata in XAML o nel codice.

Per altre informazioni sugli eventi associati in WPF, vedere Panoramica degli eventi associati.

Nomi di evento completi in XAML

Un altro utilizzo della sintassi simile alla sintassi dell'evento associato nometipo.nomeevento, che però non è esattamente un utilizzo di un evento associato, è rappresentato dall'associazione di gestori per eventi indirizzati generati da elementi figlio. I gestori vengono associati a un elemento padre comune, per sfruttare il routing degli eventi, anche se l'evento indirizzato rilevante potrebbe non essere membro dell'elemento padre comune. Si consideri di nuovo questo esempio:

<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>

In questo caso, il listener dell'elemento padre in cui viene aggiunto il gestore è .StackPanel Tuttavia, aggiunge un gestore per un evento indirizzato dichiarato e verrà generato dalla Button classe (ButtonBase in realtà, ma disponibile per Button tramite ereditarietà). Button "è proprietario" dell'evento, ma il sistema eventi indirizzato consente ai gestori di qualsiasi evento indirizzato di essere collegato a qualsiasi UIElement listener di istanza o ContentElement che potrebbe altrimenti collegare listener per un evento CLR (Common Language Runtime). Lo spazio dei nomi xmlns predefinito per questi nomi di attributi di evento qualificati è in genere lo spazio dei nomi XMLNS WPF 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 dello spazio 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. In WPF, il tunneling dei nomi degli eventi indirizzati è preceduto dalla parola "Anteprima" per convenzione. Gli eventi di input sono spesso in coppia, con un evento che rappresenta l'evento di bubbling e l'altro quello di tunneling. Ad esempio, l'evento KeyDown e l'evento PreviewKeyDown hanno la stessa firma, mentre il primo è l'evento di input di bubbling e il secondo è l'evento di input di tunneling. In alcuni casi, gli eventi di input hanno solo una versione di bubbling o solo una versione indirizzata diretta. Nella documentazione, gli argomenti relativi agli eventi indirizzati contengono riferimenti incrociati a eventi indirizzati simili con strategie di routing alternative, se disponibili, e le sezioni nelle pagine di riferimenti gestiti chiariscono 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 dall'input, ad esempio una pressione del pulsante del mouse, generi entrambi gli eventi indirizzati della coppia in sequenza. Per prima cosa, viene generato l'evento di tunneling, che avanza nella route. Successivamente, viene generato l'evento di bubbling, che avanza nella route. I due eventi condividono letteralmente la stessa istanza dei dati dell'evento, perché la RaiseEvent chiamata al metodo nella classe di implementazione che genera l'evento di bubbling rimane in ascolto dei dati dell'evento di tunneling e la riutilizza nel nuovo evento generato. I listener con gestori per l'evento di tunneling hanno l'opportunità di contrassegnare per primi l'evento indirizzato come gestito (prima i gestori di classi, quindi i gestori di istanze). Se un elemento nella route di tunneling ha contrassegnato l'evento indirizzato come gestito, i dati dell'evento già gestito vengono inviati per l'evento di bubbling e i gestori tipici associati per gli eventi di input di bubbling equivalenti non vengono richiamati. Dall'esterno, potrebbe sembrare che l'evento di bubbling gestito non sia mai stato generato. Questo comportamento di gestione è utile per la composizione di controlli in cui si vuole che tutti gli eventi di input basati su hit test o gli eventi di input basati su stato attivo vengano segnalati dal controllo finale, invece che dalle relative parti composite. L'elemento del controllo finale è più vicino alla radice nella composizione e quindi ha la possibilità di gestire tramite classi prima l'evento di tunneling ed eventualmente di "sostituire" tale evento indirizzato con un evento più specifico del controllo, come parte del codice sottostante la classe del controllo.

Come dimostrazione del 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 di un PreviewMouseDown oggetto e quindi di un MouseDown evento:

Event routing diagram

L'ordine di elaborazione degli eventi è il seguente:

  1. PreviewMouseDown (tunneling) sull'elemento radice.

  2. PreviewMouseDown (tunneling) sull'elemento intermedio 1.

  3. PreviewMouseDown (tunneling) sull'elemento di origine 2.

  4. MouseDown (bubbling) sull'elemento di origine 2.

  5. MouseDown (bubbling) sull'elemento intermedio 1.

  6. MouseDown (bubbling) sull'elemento radice.

Un delegato di un gestore di eventi indirizzati fornisce riferimenti a due oggetti: l'oggetto che ha generato l'evento e quello su cui è stato richiamato il gestore. L'oggetto in cui è stato richiamato il gestore è quello indicato dal parametro sender. L'oggetto in cui l'evento è stato generato per la Source prima volta viene segnalato dalla proprietà nei dati dell'evento. Un evento indirizzato può comunque essere generato e gestito dallo stesso oggetto, nel qual caso sender e Source sono identici (questo è il caso dei passaggi 3 e 4 nell'elenco di esempi di elaborazione eventi).

A causa del tunneling e del bubbling, gli elementi padre ricevono eventi di input in cui Source è uno dei relativi elementi figlio. Quando è importante sapere qual è l'elemento di origine, è possibile identificare l'elemento di origine accedendo alla Source proprietà .

In genere, quando l'evento di input è contrassegnato Handled, non vengono richiamati altri gestori. Solitamente è consigliabile contrassegnare gli eventi di input come gestiti non appena viene richiamato un gestore che applica la gestione logica specifica dell'applicazione al significato dell'evento di input.

L'eccezione a questa istruzione generale sullo Handled stato è che i gestori eventi di input registrati per ignorare Handled deliberatamente lo stato dei dati dell'evento vengono comunque richiamati lungo una delle due route. Per altre informazioni, vedere Eventi di anteprima e Contrassegno degli eventi indirizzati come gestiti e gestione delle classi.

Il modello di dati di evento condivisi tra eventi di tunneling e di bubbling e la generazione sequenziale di eventi prima di tunneling e quindi di bubbling non sono concetti generalmente veri per tutti gli eventi indirizzati. Questo comportamento viene implementato specificamente dal modo in cui i dispositivi di input WPF scelgono di generare e connettere le coppie di eventi di input. L'implementazione di eventi di input personalizzati è un scenario avanzato, ma si può scegliere di seguire tale modello anche per gli eventi di input personalizzati.

Alcune classi scelgono di gestire tramite classi determinati eventi di input, di solito con lo scopo di ridefinire il significato di un determinato evento di input generato dall'utente all'interno del controllo e di generare un nuovo evento. Per altre informazioni, vedere Contrassegno degli eventi indirizzati come gestiti e gestione delle classi.

Per altre informazioni sull'input e su come input ed eventi interagiscono in scenari di applicazioni tipici, vedere Cenni preliminari sull'input.

EventSetters ed EventTriggers

Negli stili, puoi includere una sintassi di gestione degli eventi XAML pre-dichiarata nel markup usando un oggetto EventSetter. Quando lo stile viene applicato, il gestore a cui si fa riferimento viene aggiunto all'istanza a cui è stato applicato lo stile. È possibile dichiarare un solo EventSetter per un evento indirizzato. Di seguito viene riportato un esempio. Si noti che il metodo b1SetColor a cui si fa riferimento qui si trova in un file code-behind.

<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>

Il vantaggio ottenuto qui è che lo stile probabilmente conterrà una grande quantità di altre informazioni che potrebbero essere applicate a qualsiasi pulsante nell'applicazione e avere parte EventSetter di tale stile promuove il riutilizzo del codice anche a livello di markup. Inoltre, un EventSetter metodo astrae i nomi per i gestori a un ulteriore passo 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 usare solo gli eventi indirizzati per un oggetto EventTrigger. In genere, un oggetto EventTrigger viene dichiarato come parte di uno stile, ma può EventTrigger anche 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 i trigger di evento per controllare uno storyboard dopo il relativo avvio.

Altre informazioni sugli eventi indirizzati

Questo argomento illustra gli eventi indirizzati principalmente con lo scopo di descrivere i concetti di base e di fornire istruzioni su come e quando rispondere agli eventi indirizzati già presenti nei vari controlli ed elementi di base. È tuttavia possibile creare un evento indirizzato personalizzato in una classe personalizzata insieme a tutto il supporto necessario, come delegati e classi di dati di evento specializzati. Il proprietario dell'evento indirizzato può essere qualsiasi classe, ma gli eventi indirizzati devono essere generati da 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