Panoramica degli eventi associati (WPF .NET)
Extensible Application Markup Language (XAML) definisce un componente del linguaggio e un tipo di evento denominato evento associato. Gli eventi associati possono essere usati per definire un nuovo evento instradato in una classe non elementare e attivare tale evento su qualsiasi elemento dell'albero. A tale scopo, è necessario registrare l'evento collegato come evento instradato e specificare codice di supporto specifico che supporta la funzionalità dell'evento collegato. Poiché gli eventi associati vengono registrati come eventi indirizzati, quando generati su un elemento vengono propagati attraverso l'albero degli elementi.
Prerequisiti
L'articolo presuppone una conoscenza di base degli eventi instradati di Windows Presentation Foundation (WPF) e che tu abbia letto Panoramica degli eventi instradati e XAML in WPF. Per seguire gli esempi in questo articolo, è utile se si ha familiarità con XAML e si sa come scrivere applicazioni WPF.
Sintassi degli eventi associati
Nella sintassi XAML, un evento associato viene specificato dal nome dell'evento e tipo di proprietario, sotto forma di <owner type>.<event name>
. Dato che il nome dell'evento è qualificato con il nome del tipo di proprietario, la sintassi consente di associare l'evento a qualsiasi elemento che possa essere istanziato. Questa sintassi è applicabile anche ai gestori per gli eventi instradati regolari che si connettono a un elemento arbitrario lungo il percorso dell'evento.
La sintassi dell'attributo XAML seguente collega il gestore AquariumFilter_Clean
per l'evento associato AquariumFilter.Clean
all'elemento aquarium1
:
<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>
In questo esempio, il prefisso aqua:
è necessario perché le classi AquariumFilter
e Aquarium
esistono in uno spazio dei nomi e un assembly CLR (Common Language Runtime) diversi.
È anche possibile collegare gestori per gli eventi associati nel code-behind. A tale scopo, chiamare il metodo AddHandler sull'oggetto a cui deve essere associato il gestore e passare l'identificatore dell'evento e il gestore come parametri al metodo.
Come WPF implementa gli eventi associati
Gli eventi associati WPF vengono implementati come eventi indirizzati supportati da un campo RoutedEvent. Di conseguenza, gli eventi associati vengono propagati attraverso l'albero degli elementi dopo che sono stati generati. In genere, l'oggetto che solleva l'evento allegato, noto come sorgente dell'evento, è una sorgente di sistema o di servizio. Le origini di sistema o di servizio non fanno parte direttamente dell'albero degli elementi. Per altri eventi associati, l'origine evento potrebbe essere un elemento nell'albero, ad esempio un componente all'interno di un controllo composito.
Scenari di eventi associati
In WPF, gli eventi associati vengono usati in determinate aree di funzionalità in cui è presente un'astrazione a livello di servizio. Ad esempio, WPF usa gli eventi allegati abilitati dalle classi Mouse statiche o Validation. Le classi che interagiscono con o usano un servizio possono interagire con un evento usando la sintassi di eventi associata o visualizzare l'evento associato come evento indirizzato. Quest'ultima opzione fa parte del modo in cui una classe potrebbe integrare le funzionalità del servizio.
Il sistema di input WPF usa ampiamente gli eventi associati. Tuttavia, quasi tutti gli eventi associati emergono come eventi non associati indirizzati equivalenti attraverso elementi di base. Ogni evento di input instradato è un membro della classe dell'elemento di base ed è associato a un evento CLR "wrapper". Raramente si useranno o si gestiranno direttamente gli eventi associati. Ad esempio, è più semplice gestire l'evento allegato Mouse.MouseDown sottostante in un UIElement tramite l'evento instradato UIElement.MouseDown equivalente rispetto all'uso della sintassi degli eventi allegati in XAML o codice sottostante.
Gli eventi associati servono a scopo di architettura abilitando l'espansione futura dei dispositivi di input. Ad esempio, un nuovo dispositivo di input dovrà generare solo Mouse.MouseDown
per simulare l'input del mouse e non sarebbe necessario derivare da Mouse
a tale scopo. Questo scenario implica la gestione del codice dell'evento, poiché la gestione XAML dell'evento associato non sarebbe rilevante.
Gestire un evento collegato
Il processo di codifica e gestione di un evento associato è fondamentalmente uguale a quello di un evento indirizzato non collegato.
Come indicato precedentemente, gli eventi associati WPF esistenti generalmente non sono destinati a essere gestiti direttamente in WPF. Più spesso, lo scopo di un evento associato è consentire a un elemento all'interno di un controllo composito di segnalarne lo stato a un elemento padre all'interno del controllo. In questo scenario, l'evento viene generato nel codice e si basa sulla gestione delle classi nella classe padre pertinente. Ad esempio, si prevede che gli elementi all'interno di un Selector generino l'evento associato Selected, che viene quindi gestito dalla classe Selector
. La classe Selector
ha il potenziale per convertire l'evento Selected
nell'evento indirizzato SelectionChanged. Per ulteriori informazioni sugli eventi instradati e sulla gestione delle classi, vedere Contrassegnare come gestiti gli eventi instradati egestione delle classi.
Definire un evento associato personalizzato
Se si deriva da classi di base WPF comuni, è possibile implementare l'evento associato personalizzato includendo due metodi di accesso nella classe. Questi metodi sono:
Un metodo gestore eventi Add<>, con un primo parametro che rappresenta l'elemento al quale è associato il gestore dell'evento e un secondo parametro che è il gestore dell'evento da aggiungere. Il metodo deve essere
public
estatic
, senza alcun valore restituito. Il metodo chiama il metodo della classe base AddHandler, passando l'evento instradato e il gestore come argomenti. Questo metodo supporta la sintassi dell'attributo XAML per associare un gestore eventi a un elemento. Questo metodo consente inoltre l'accesso del codice all'archivio del gestore eventi per l'evento associato.Un metodo Remove<nome dell'evento>Handler, con un primo parametro che rappresenta l'elemento a cui è associato il gestore eventi e un secondo parametro che è il gestore eventi da rimuovere. Il metodo deve essere
public
estatic
, senza alcun valore restituito. Il metodo chiama il metodo della classe base RemoveHandler, passando l'evento instradato e il gestore come argomenti. Questo metodo consente l'accesso del codice all'archivio del gestore eventi per l'evento associato.
WPF implementa gli eventi associati come eventi indirizzati perché l'identificatore di un RoutedEvent è definito dal sistema di eventi WPF. Inoltre, il routing di un evento è un'estensione naturale del concetto a livello di linguaggio XAML di un evento associato. Questa strategia di implementazione limita la gestione degli eventi associati alle classi derivate dalle UIElement o dalle ContentElement, perché solo quelle classi hanno le implementazioni AddHandler.
Ad esempio, il codice seguente definisce l'evento associato Clean
sulla classe proprietaria AquariumFilter
, che non è una classe di elementi. Il codice definisce l'evento associato come evento indirizzato e implementa i metodi di accesso necessari.
public class AquariumFilter
{
// Register a custom routed event using the bubble routing strategy.
public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
"Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
// Provide an add handler accessor method for the Clean event.
public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
{
if (dependencyObject is not UIElement uiElement)
return;
uiElement.AddHandler(CleanEvent, handler);
}
// Provide a remove handler accessor method for the Clean event.
public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
{
if (dependencyObject is not UIElement uiElement)
return;
uiElement.RemoveHandler(CleanEvent, handler);
}
}
Public Class AquariumFilter
' Register a custom routed event using the bubble routing strategy.
Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
"Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
' Provide an add handler accessor method for the Clean event.
Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)
If uiElement IsNot Nothing Then
uiElement.[AddHandler](CleanEvent, handler)
End If
End Sub
' Provide a remove handler accessor method for the Clean event.
Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)
If uiElement IsNot Nothing Then
uiElement.[RemoveHandler](CleanEvent, handler)
End If
End Sub
End Class
Il metodo RegisterRoutedEvent che restituisce l'identificatore di evento associato è lo stesso metodo usato per registrare eventi indirizzati non associati. Gli eventi instradati collegati e non collegati vengono registrati in un archivio dati interno centralizzato. Questa implementazione dell'archivio eventi abilita il concetto di "eventi come interfaccia" descritto in panoramica degli eventi indirizzati.
A differenza dell'evento CLR "wrapper" utilizzato per supportare eventi indirizzati non collegati, i metodi accessor degli eventi allegati possono essere implementati nelle classi che non derivano da UIElement o ContentElement. Ciò è possibile perché il codice di backup dell'evento associato chiama i metodi UIElement.AddHandler e UIElement.RemoveHandler su un'istanza di UIElement
passata. Al contrario, il wrapper CLR per gli eventi indirizzati non collegati chiama tali metodi direttamente nella classe proprietaria, in modo che la classe debba derivare da UIElement
.
Generare un evento associato WPF
Il processo di generazione di un evento associato è essenzialmente uguale a quello di un routed event non associato.
In genere, il tuo codice non dovrà generare alcun evento collegato definito da WPF esistente poiché questi eventi seguono il modello concettuale generale di "servizio". In tale modello, le classi di servizio, ad esempio InputManager, sono responsabili della generazione di eventi associati definiti da WPF.
Quando si definisce un evento associato personalizzato usando il modello WPF di basare gli eventi associati su eventi indirizzati, usare il metodo UIElement.RaiseEvent per generare un evento associato in qualsiasi UIElement o ContentElement. Quando si genera un evento instradato, indipendentemente dal fatto che sia associato o meno, è necessario designare un elemento nell'albero degli elementi come origine dell'evento. Quella fonte viene quindi segnalata come chiamante RaiseEvent
. Ad esempio, per generare l'evento indirizzato collegato AquariumFilter.Clean
in aquarium1
:
aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))
Nell'esempio precedente, aquarium1
è la fonte dell'evento.
Vedere anche
.NET Desktop feedback