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

Importante

La documentazione di Desktop Guide per .NET 7 e .NET 6 è in fase di costruzione.

Prerequisiti

L'articolo presuppone una conoscenza di base degli eventi indirizzati di Windows Presentation Foundation (WPF) e che hai letto panoramica degli eventi indirizzati 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 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.

La sintassi dell'attributo XAML seguente collega il AquariumFilter_Clean gestore per l'evento AquariumFilter.Clean associato all'elemento aquarium1 :

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

In questo esempio, il aqua: prefisso è necessario perché le AquariumFilter classi 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 AddHandler metodo sull'oggetto a cui deve essere associato il gestore e passare l'identificatore e il gestore dell'evento come parametri al metodo .

Come WPF implementa gli eventi associati

Gli eventi associati WPF vengono implementati come eventi indirizzati supportati da un RoutedEvent campo. Di conseguenza, gli eventi associati vengono propagati attraverso l'albero degli elementi dopo che sono stati generati. In genere, l'oggetto che genera l'evento associato, noto come origine evento, è un'origine di sistema o di servizio. Le origini di sistema o di servizio non fanno parte diretta 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 associati abilitati dalle classi statiche Mouse 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 vengono visualizzati come eventi indirizzati non associati equivalenti tramite elementi di base. Ogni evento di input indirizzato è un membro della classe dell'elemento di base e viene supportato con un evento CLR "wrapper". 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.

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 per simulare Mouse.MouseDown 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 associato

Il processo di codifica e gestione di un evento associato è fondamentalmente uguale a quello di un evento indirizzato non collegato.

Come indicato in precedenza, gli eventi associati WPF esistenti in genere non devono 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 oggetto generino l'evento Selected associato, che viene quindi gestito dalla Selector classe . La Selector classe converte potenzialmente l'evento Selected nell'evento SelectionChanged indirizzato. Per altre informazioni sugli eventi indirizzati e sulla gestione delle classi, vedere Contrassegnare gli eventi indirizzati come gestiti e la gestione 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:

  • Metodo Add<event name>Handler , con un primo parametro che rappresenta l'elemento su cui è associato il gestore eventi e un secondo parametro che rappresenta il gestore eventi da aggiungere. Il metodo deve essere public e static, senza alcun valore restituito. Il metodo chiama il metodo della AddHandler classe base, passando l'evento indirizzato 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.

  • Metodo Remove<event name>Handler , con un primo parametro che rappresenta l'elemento in cui è associato il gestore eventi e un secondo parametro che rappresenta il gestore eventi da rimuovere. Il metodo deve essere public e static, senza alcun valore restituito. Il metodo chiama il metodo della RemoveHandler classe base, passando l'evento indirizzato 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 oggetto è 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 a UIElement classi derivate o ContentElement classi derivate, perché solo tali classi dispongono AddHandler di implementazioni.

Ad esempio, il codice seguente definisce l'evento Clean associato nella AquariumFilter classe proprietario, che non è una classe di elemento. 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 RegisterRoutedEvent metodo che restituisce l'identificatore di evento associato è lo stesso metodo usato per registrare eventi indirizzati non associati. Gli eventi indirizzati collegati e non collegati vengono registrati in un archivio 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" usato per eseguire il backing di eventi indirizzati non collegati, i metodi della funzione di accesso agli eventi associati possono essere implementati nelle classi che non derivano da UIElement o ContentElement. Ciò è possibile perché il codice di backup dell'evento associato chiama i UIElement.AddHandler metodi e UIElement.RemoveHandler in un'istanza 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 evento indirizzato non collegato.

In genere, il codice non dovrà generare eventi associati definiti da WPF esistenti perché questi eventi seguono il modello concettuale generale "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 sugli eventi indirizzati, usare il UIElement.RaiseEvent metodo per generare un evento associato in qualsiasi UIElement oggetto o ContentElement. Quando si genera un evento indirizzato, indipendentemente dal fatto che sia associato o meno, è necessario designare un elemento nell'albero degli elementi come origine evento. Tale origine viene quindi segnalata come RaiseEvent chiamante. Ad esempio, per generare l'evento AquariumFilter.Clean indirizzato associato in aquarium1:

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

Nell'esempio precedente è aquarium1 l'origine evento.

Vedi anche