Vue d’ensemble des événements attachés (WPF .NET)

Le langage XAML (Extensible Application Markup Language) définit un composant de langage et un type d’événement appelé événement attaché. Les événements attachés peuvent être utilisés pour définir un nouvel événement routé dans une classe non-élément et déclencher cet événement sur n’importe quel élément de votre arborescence. Pour ce faire, vous devez inscrire l’événement attaché en tant qu’événement routé et fournir un code de stockage spécifique qui prend en charge les fonctionnalités d’événement attachées. Étant donné que les événements joints sont inscrits en tant qu’événements routés, lorsqu’ils sont déclenchés sur un élément qu’ils propagent à travers l’arborescence d’éléments.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Prérequis

L’article suppose une connaissance de base des événements routés windows Presentation Foundation (WPF) et que vous avez lu la vue d’ensemble des événements routés et XAML dans WPF. Pour suivre les exemples de cet article, il est utile si vous êtes familiarisé avec XAML et que vous savez comment écrire des applications WPF.

Syntaxe de l’événement attaché

Dans la syntaxe XAML, un événement attaché est spécifié par son nom d’événement et son type de propriétaire, sous la forme .<owner type>.<event name> Étant donné que le nom de l’événement est qualifié avec le nom de son type de propriétaire, la syntaxe permet à l’événement d’être attaché à n’importe quel élément pouvant être instancié. Cette syntaxe s’applique également aux gestionnaires pour les événements routés réguliers qui s’attachent à un élément arbitraire le long de l’itinéraire d’événements.

La syntaxe d’attribut XAML suivante attache le AquariumFilter_Clean gestionnaire de l’événement AquariumFilter.Clean attaché à l’élément aquarium1 :

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

Dans cet exemple, le aqua: préfixe est nécessaire, car les AquariumAquariumFilter classes existent dans un autre espace de noms et assembly CLR (Common Language Runtime).

Vous pouvez également attacher des gestionnaires pour les événements attachés dans le code-behind. Pour ce faire, appelez la AddHandler méthode sur l’objet auquel le gestionnaire doit attacher et transmettre l’identificateur d’événement et le gestionnaire en tant que paramètres à la méthode.

Comment WPF implémente les événements attachés

Les événements joints WPF sont implémentés en tant qu’événements routés soutenus par un RoutedEvent champ. Par conséquent, les événements attachés se propagent dans l’arborescence d’éléments après leur levée. En règle générale, l’objet qui déclenche l’événement attaché, appelé source d’événement, est une source de système ou de service. Les sources système ou de service ne font pas partie directe de l’arborescence d’éléments. Pour d’autres événements attachés, la source d’événement peut être un élément de l’arborescence, tel qu’un composant dans un contrôle composite.

Scénarios d’événements attachés

Dans WPF, les événements attachés sont utilisés dans certaines zones de fonctionnalités où il existe une abstraction au niveau du service. Par exemple, WPF utilise des événements attachés activés par les classes ou Validation statiquesMouse. Les classes qui interagissent avec ou utilisent un service peuvent interagir avec un événement à l’aide de la syntaxe d’événement attaché ou exposer l’événement attaché en tant qu’événement routé. Cette dernière option fait partie de la façon dont une classe peut intégrer les fonctionnalités du service.

Le système d’entrée WPF utilise largement les événements attachés. Toutefois, presque tous ces événements attachés sont exposés comme des événements routés non attachés équivalents par le biais d’éléments de base. Chaque événement d’entrée routé est membre de la classe d’élément de base et est soutenu par un événement CLR « wrapper ». Vous utiliserez rarement ou gérez directement les événements attachés. Par exemple, il est plus facile de gérer l’événement attaché Mouse.MouseDown sous-jacent sur un UIElement événement routé équivalent UIElement.MouseDown qu’à l’aide de la syntaxe d’événement attachée en XAML ou code-behind.

Les événements attachés servent un objectif d’architecture en permettant l’expansion future des appareils d’entrée. Par exemple, un nouvel appareil d’entrée n’a besoin que de déclencher Mouse.MouseDown pour simuler l’entrée de la souris, et il n’aurait pas besoin de dériver de Mouse cette opération. Ce scénario implique la gestion du code de l’événement, car la gestion XAML de l’événement attaché n’est pas pertinente.

Gérer un événement attaché

Le processus de codage et de gestion d’un événement attaché est essentiellement identique à celui d’un événement routé non attaché.

Comme indiqué précédemment, les événements joints WPF existants ne sont généralement pas destinés à être gérés directement dans WPF. Plus souvent, l’objectif d’un événement attaché est de permettre à un élément au sein d’un contrôle composite de signaler son état à un élément parent dans le contrôle. Dans ce scénario, l’événement est déclenché dans le code et s’appuie sur la gestion des classes dans la classe parente appropriée. Par exemple, les éléments d’un élément Selector sont censés déclencher l’événement Selected attaché, qui est ensuite géré par la Selector classe. La Selector classe convertit potentiellement l’événement Selected en événement SelectionChanged routé. Pour plus d’informations sur les événements routés et la gestion des classes, consultez Marquage des événements routés comme gérés et gestion des classes.

Définir un événement attaché personnalisé

Si vous dérivez de classes de base WPF courantes, vous pouvez implémenter votre événement attaché personnalisé en incluant deux méthodes d’accesseur dans votre classe. Ces méthodes sont les suivantes :

  • Méthode Add<event name>Handler , avec un premier paramètre sur lequel le gestionnaire d’événements est attaché, et un deuxième paramètre qui est le gestionnaire d’événements à ajouter. La méthode doit être public et static, sans valeur de retour. La méthode appelle la AddHandler méthode de classe de base, en passant l’événement routé et le gestionnaire en tant qu’arguments. Cette méthode prend en charge la syntaxe d’attribut XAML pour attacher un gestionnaire d’événements à un élément. Cette méthode permet également l’accès au code au magasin de gestionnaires d’événements pour l’événement attaché.

  • Méthode Remove<event name>Handler , avec un premier paramètre sur lequel le gestionnaire d’événements est attaché, et un deuxième paramètre qui est le gestionnaire d’événements à supprimer. La méthode doit être public et static, sans valeur de retour. La méthode appelle la RemoveHandler méthode de classe de base, en passant l’événement routé et le gestionnaire en tant qu’arguments. Cette méthode permet l’accès au code au magasin de gestionnaires d’événements pour l’événement attaché.

WPF implémente des événements attachés en tant qu’événements routés, car l’identificateur d’un RoutedEvent est défini par le système d’événements WPF. En outre, le routage d’un événement est une extension naturelle du concept de langage XAML d’un événement attaché. Cette stratégie d’implémentation limite la gestion des événements attachés aux UIElement classes dérivées ou ContentElement aux classes dérivées, car seules ces classes ont AddHandler des implémentations.

Par exemple, le code suivant définit l’événement Clean attaché sur la AquariumFilter classe propriétaire, qui n’est pas une classe d’élément. Le code définit l’événement attaché en tant qu’événement routé et implémente les méthodes d’accesseur requises.

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

La RegisterRoutedEvent méthode qui retourne l’identificateur d’événement attaché est la même méthode que celle utilisée pour inscrire des événements routés non attachés. Les événements routés attachés et non attachés sont enregistrés dans un magasin interne centralisé. Cette implémentation de magasin d’événements active le concept « événements en tant qu’interface » abordé dans la vue d’ensemble des événements routés.

Contrairement à l’événement CLR « wrapper » utilisé pour sauvegarder les événements routés non attachés, les méthodes d’accesseur d’événements jointes peuvent être implémentées dans des classes qui ne dérivent pas ou ContentElementqui ne dérivent UIElement pas . Cela est possible, car le code de stockage d’événements attaché appelle les méthodes et UIElement.RemoveHandler les UIElement.AddHandler méthodes sur une instance passéeUIElement. En revanche, le wrapper CLR pour les événements routés non attachés appelle ces méthodes directement sur la classe propriétaire, de sorte que cette classe doit dériver de UIElement.

Déclencher un événement attaché WPF

Le processus de déclenchement d’un événement attaché est essentiellement identique à celui d’un événement routé non attaché.

En règle générale, votre code n’a pas besoin de déclencher d’événements joints définis par WPF existants, car ces événements suivent le modèle conceptuel « service » général. Dans ce modèle, les classes de service, telles que InputManager, sont chargées de déclencher des événements joints définis par WPF.

Lors de la définition d’un événement attaché personnalisé à l’aide du modèle WPF de base d’événements attachés sur les événements routés, utilisez la UIElement.RaiseEvent méthode pour déclencher un événement attaché sur n’importe quel UIElement ou ContentElement. Lorsque vous déclenchez un événement routé, qu’il soit attaché ou non, vous devez désigner un élément dans votre arborescence d’éléments comme source d’événement. Cette source est ensuite signalée en tant qu’appelant RaiseEvent . Par exemple, pour déclencher l’événement AquariumFilter.Clean routé attaché sur aquarium1:

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

Dans l’exemple précédent, aquarium1 est la source d’événement.

Voir aussi