Comportements
Les comportements de l’interface utilisateur d’application multiplateforme .NET (.NET MAUI) vous permettent d’ajouter des fonctionnalités supplémentaires aux contrôles d’interface utilisateur, tels que Button ou Entry, sans avoir à sous-classer les contrôles. Au lieu de cela, les fonctionnalités supplémentaires sont implémentées dans une classe Behavior et attachées au contrôle.
Les comportements peuvent être utilisés pour ajouter différentes fonctionnalités aux contrôles d’interface utilisateur, tels que :
- Validations d’entrée. Les comportements peuvent être utilisés avec des contrôles d’entrée pour s’assurer que les données sont valides. Par exemple, vous pouvez écrire un comportement pour un Entry pour vous assurer qu’un numéro de téléphone d’adresse e-mail est au format correct.
- Amélioration de l’interface utilisateur. Les comportements peuvent être utilisés pour améliorer les contrôles d’interface utilisateur dans votre application. Par exemple, vous pouvez écrire un comportement pour un Button pour le faire secouer lorsqu’il est cliqué ou modifier la couleur.
- Réponses d’exécution. Les comportements peuvent être utilisés pour faire réagir les contrôles à différentes situations. Par exemple, vous pouvez enregistrer automatiquement l’entrée utilisateur dans un Entry lorsqu’un utilisateur termine la saisie.
.NET MAUI prend en charge trois types de comportements différents :
- Les comportements attachés sont des classes
static
avec une ou plusieurs propriétés attachées. Pour plus d’informations sur les comportements associés, consultez comportements associés. - Les comportements .NET MAUI sont des classes qui dérivent de la classe Behavior ou Behavior<T>, où
T
est le type du contrôle auquel le comportement doit s’appliquer. Pour plus d'informations, consultez .NET MAUI comportements. - Les comportements de plateforme sont des classes qui dérivent de la classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>. Ces comportements peuvent répondre à des conditions et événements arbitraires sur un contrôle natif. Pour plus d’informations, consultez comportements de la plateforme.
Comportements associés
Les comportements attachés sont des classes statiques avec une ou plusieurs propriétés jointes. Une propriété jointe est un type spécial de propriété pouvant être liée. Elles sont définies dans une classe, mais attachées à d’autres objets, et elles sont reconnaissables en XAML en tant qu’attributs qui contiennent une classe et un nom de propriété séparés par un point. Pour plus d’informations sur les « propriétés attachées », consultez propriétés attachées.
Une propriété jointe peut définir un délégué propertyChanged
qui sera exécuté lorsque la valeur de la propriété change, par exemple lorsque la propriété est définie sur un contrôle. Lorsque le délégué propertyChanged
s’exécute, on lui passe une référence au contrôle sur lequel il est attaché ainsi que les paramètres contenant les anciennes et nouvelles valeurs de la propriété. Ce délégué peut être utilisé pour ajouter de nouvelles fonctionnalités au contrôle auquel la propriété est attachée en manipulant la référence passée, comme suit :
- Le délégué
propertyChanged
convertit la référence de contrôle, qui est reçue en tant que BindableObject, au type de contrôle que le comportement est conçu pour améliorer. - Le délégué
propertyChanged
modifie les propriétés du contrôle, appelle les méthodes du contrôle ou inscrit des gestionnaires d’événements pour les événements exposés par le contrôle afin d’implémenter la fonctionnalité de comportement principale.
Avertissement
Les comportements attachés sont définis dans une classe static
, avec static
propriétés et méthodes. Cela rend difficile la création de comportements liés qui ont un état.
Créer un comportement attaché
Un comportement attaché peut être implémenté en créant une classe statique qui contient une propriété jointe qui spécifie un délégué propertyChanged
.
L’exemple suivant montre la classe AttachedNumericValidationBehavior
, qui met en surbrillance la valeur entrée par l’utilisateur dans un contrôle Entry en rouge s’il n’est pas un double
:
public static class AttachedNumericValidationBehavior
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(AttachedNumericValidationBehavior), false, propertyChanged: OnAttachBehaviorChanged);
public static bool GetAttachBehavior(BindableObject view)
{
return (bool)view.GetValue(AttachBehaviorProperty);
}
public static void SetAttachBehavior(BindableObject view, bool value)
{
view.SetValue(AttachBehaviorProperty, value);
}
static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
{
Entry entry = view as Entry;
if (entry == null)
{
return;
}
bool attachBehavior = (bool)newValue;
if (attachBehavior)
{
entry.TextChanged += OnEntryTextChanged;
}
else
{
entry.TextChanged -= OnEntryTextChanged;
}
}
static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
double result;
bool isValid = double.TryParse(args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
}
}
Dans cet exemple, la classe AttachedNumericValidationBehavior
contient une propriété jointe nommée AttachBehavior
avec un static
getter et setter, qui contrôle l’ajout ou la suppression du comportement au contrôle auquel il sera attaché. Cette propriété jointe inscrit la méthode OnAttachBehaviorChanged
qui sera exécutée lorsque la valeur de la propriété change. Cette méthode enregistre ou désenregistre un gestionnaire d'événement pour l'événement TextChanged
, basé sur la valeur de la propriété jointe AttachBehavior
. La fonctionnalité principale du comportement est fournie par la méthode OnEntryTextChanged
, qui analyse la valeur entrée dans l'Entry et définit la propriété TextColor
sur rouge si la valeur n’est pas un double
.
Consommer un comportement attaché
Un comportement attaché peut être consommé en définissant sa propriété jointe sur le contrôle cible.
L’exemple suivant montre l’utilisation de la classe AttachedNumericValidationBehavior
sur un Entry en ajoutant la propriété jointe AttachBehavior
au Entry:
<ContentPage ...
xmlns:local="clr-namespace:BehaviorsDemos">
<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="true" />
</ContentPage>
La Entry équivalente en C# est illustrée dans l’exemple de code suivant :
Entry entry = new Entry { Placeholder = "Enter a System.Double" };
AttachedNumericValidationBehavior.SetAttachBehavior(entry, true);
La capture d’écran suivante montre le comportement attaché répondant à une entrée non valide :
capture d'écran
Note
Les comportements attachés sont écrits pour un type de contrôle spécifique (ou une superclasse qui peut s’appliquer à de nombreux contrôles), et ils ne doivent être ajoutés qu’à un contrôle compatible.
Supprimer un comportement attaché
La classe AttachedNumericValidationBehavior
peut être supprimée d’un contrôle en définissant la propriété jointe AttachBehavior
sur false
:
<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="false" />
Lors de l’exécution, la méthode OnAttachBehaviorChanged
est exécutée lorsque la valeur de la propriété jointe AttachBehavior
est définie sur false
. La méthode OnAttachBehaviorChanged
désinscrira ensuite le gestionnaire d’événements pour l’événement TextChanged
, en vous assurant que le comportement n’est pas exécuté lorsque vous interagissez avec le contrôle.
Comportements MAUI .NET
Les comportements MAUI .NET sont créés en dérivant de la classe Behavior ou Behavior<T>.
Le processus de création d’un comportement MAUI .NET est le suivant :
- Créez une classe qui hérite de la classe Behavior ou Behavior<T>, où
T
est le type du contrôle auquel le comportement doit s’appliquer. - Remplacez la méthode OnAttachedTo pour effectuer toute configuration requise.
- Remplacez la méthode OnDetachingFrom pour effectuer tout nettoyage requis.
- Implémentez les fonctionnalités principales du comportement.
Cela entraîne la structure indiquée dans l’exemple suivant :
public class MyBehavior : Behavior<View>
{
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
// Perform setup
}
protected override void OnDetachingFrom(View bindable)
{
base.OnDetachingFrom(bindable);
// Perform clean up
}
// Behavior implementation
}
La méthode OnAttachedTo est appelée immédiatement après l’attachement du comportement à un contrôle. Cette méthode reçoit une référence au contrôle auquel il est attaché et peut être utilisée pour inscrire des gestionnaires d’événements ou effectuer d’autres configurations requises pour prendre en charge la fonctionnalité de comportement. Par exemple, vous pouvez vous abonner à un événement sur un élément de contrôle. La fonctionnalité de comportement est ensuite implémentée dans le gestionnaire d’événements pour l’événement.
La méthode OnDetachingFrom est appelée lorsque le comportement est supprimé du contrôle. Cette méthode reçoit une référence au contrôle auquel elle est attachée et est utilisée pour effectuer tout nettoyage requis. Par exemple, vous pouvez vous désabonner d’un événement sur un contrôle pour éviter les fuites de mémoire.
Le comportement peut ensuite être consommé en l’attachant à la collection Behaviors du contrôle.
Créer un comportement MAUI .NET
Un comportement MAUI .NET peut être implémenté en créant une classe qui dérive de la classe Behavior ou Behavior<T>, et en remplaçant les méthodes OnAttachedTo et OnDetachingFrom.
L’exemple suivant montre la classe NumericValidationBehavior
, qui met en surbrillance la valeur entrée par l’utilisateur dans un contrôle Entry en rouge s’il n’est pas un double
:
public class NumericValidationBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
double result;
bool isValid = double.TryParse(args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
}
}
Dans cet exemple, la classe NumericValidationBehavior
dérive de la classe Behavior<T>, où T
est un Entry. La méthode OnAttachedTo inscrit un gestionnaire d’événements pour l’événement TextChanged
, avec la méthode OnDetachingFrom désinscrire l’événement TextChanged
pour empêcher les fuites de mémoire. La fonctionnalité principale du comportement est fournie par la méthode OnEntryTextChanged
, qui analyse la valeur entrée dans l'Entry et définit la propriété TextColor
sur rouge si la valeur n’est pas un double
.
Important
.NET MAUI ne définit pas la BindingContext
d’un comportement, car les comportements peuvent être partagés et appliqués à plusieurs contrôles par le biais de styles.
Consommer un comportement MAUI .NET
Chaque contrôle .NET MAUI a une collection de Behaviors, auquel un ou plusieurs comportements peuvent être ajoutés :
<Entry Placeholder="Enter a System.Double">
<Entry.Behaviors>
<local:NumericValidationBehavior />
</Entry.Behaviors>
</Entry>
La Entry équivalente en C# est illustrée dans l’exemple de code suivant :
Entry entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add(new NumericValidationBehavior());
La capture d’écran suivante montre le comportement MAUI .NET répondant à une entrée non valide :
La capture d’écran
Avertissement
Les comportements MAUI .NET sont écrits pour un type de contrôle spécifique (ou une superclasse qui peut s’appliquer à de nombreux contrôles), et ils ne doivent être ajoutés qu’à un contrôle compatible. Toute tentative d’attachement d’un comportement MAUI .NET à un contrôle incompatible entraîne la levée d’une exception.
Consommer un comportement MAUI .NET avec un style
Les comportements MAUI .NET peuvent être consommés par un style explicite ou implicite. Toutefois, la création d’un style qui définit la propriété Behaviors d’un contrôle n’est pas possible, car la propriété est en lecture seule. La solution consiste à ajouter une propriété jointe à la classe de comportement qui contrôle l’ajout et la suppression du comportement. Le processus est le suivant :
- Ajoutez une propriété jointe à la classe de comportement qui sera utilisée pour contrôler l’ajout ou la suppression du comportement au contrôle auquel le comportement sera attaché. Vérifiez que la propriété jointe inscrit un délégué
propertyChanged
qui sera exécuté lorsque la valeur de la propriété change. - Créez un
static
getter et setter pour la propriété jointe. - Implémentez la logique dans le délégué
propertyChanged
pour ajouter et supprimer le comportement.
L’exemple suivant montre la classe NumericValidationStyleBehavior
, qui a une propriété jointe qui contrôle l’ajout et la suppression du comportement :
public class NumericValidationStyleBehavior : Behavior<Entry>
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(NumericValidationStyleBehavior), false, propertyChanged: OnAttachBehaviorChanged);
public static bool GetAttachBehavior(BindableObject view)
{
return (bool)view.GetValue(AttachBehaviorProperty);
}
public static void SetAttachBehavior(BindableObject view, bool value)
{
view.SetValue(AttachBehaviorProperty, value);
}
static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
{
Entry entry = view as Entry;
if (entry == null)
{
return;
}
bool attachBehavior = (bool)newValue;
if (attachBehavior)
{
entry.Behaviors.Add(new NumericValidationStyleBehavior());
}
else
{
Behavior toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationStyleBehavior);
if (toRemove != null)
{
entry.Behaviors.Remove(toRemove);
}
}
}
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
double result;
bool isValid = double.TryParse(args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
}
}
Dans cet exemple, la classe NumericValidationStyleBehavior
contient une propriété jointe nommée AttachBehavior
avec un static
getter et setter, qui contrôle l’ajout ou la suppression du comportement au contrôle auquel il sera attaché. Cette propriété jointe inscrit la méthode OnAttachBehaviorChanged
qui sera exécutée lorsque la valeur de la propriété change. Cette méthode ajoute ou supprime le comportement au contrôle, en fonction de la valeur de la propriété jointe AttachBehavior
.
L’exemple de code suivant montre un style explicite pour l'NumericValidationStyleBehavior
qui utilise la propriété jointe AttachBehavior
et qui peut être appliqué aux contrôles Entry :
<Style x:Key="NumericValidationStyle" TargetType="Entry">
<Style.Setters>
<Setter Property="local:NumericValidationStyleBehavior.AttachBehavior" Value="true" />
</Style.Setters>
</Style>
Le Style peut être appliqué à un Entry en définissant sa propriété Style sur le style à l’aide de l’extension de balisage StaticResource
:
<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">
Pour plus d’informations sur les styles, consultez Styles.
Note
Bien que vous puissiez ajouter des propriétés pouvant être liées à un comportement défini ou interrogé en XAML, si vous créez des comportements dont l’état ne doit pas être partagé entre les contrôles d’un Style dans un ResourceDictionary.
Supprimer un comportement MAUI .NET
La méthode OnDetachingFrom est appelée lorsqu’un comportement est supprimé d’un contrôle et est utilisé pour effectuer tout nettoyage requis, tel que la désinscrire d’un événement pour empêcher une fuite de mémoire. Toutefois, les comportements ne sont pas implicitement supprimés des contrôles, sauf si la collection de Behaviors du contrôle est modifiée par la méthode Remove
ou Clear
:
Behavior toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationStyleBehavior);
if (toRemove != null)
{
entry.Behaviors.Remove(toRemove);
}
Vous pouvez également effacer la collection Behaviors du contrôle :
entry.Behaviors.Clear();
Note
Les comportements MAUI .NET ne sont pas implicitement supprimés des contrôles lorsque les pages sont extraites de la pile de navigation. Au lieu de cela, elles doivent être explicitement supprimées avant que les pages ne sortent de leur portée.
Comportements de plateforme
Les comportements de plateforme sont créés en dérivant de la classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>. Ils répondent à des conditions et événements arbitraires sur un contrôle natif.
Un comportement de plateforme peut être implémenté par le biais d’une compilation conditionnelle ou de classes partielles. L’approche adoptée ici consiste à utiliser des classes partielles, où un comportement de plateforme se compose généralement d’une classe partielle multiplateforme qui définit l’API de comportement et d’une classe partielle native qui implémente le comportement sur chaque plateforme. Au moment de la génération, le multi-ciblage combine les classes partielles pour générer le comportement de la plateforme sur chaque plateforme.
Le processus de création d’un comportement de plateforme est le suivant :
Créez une classe partielle multiplateforme qui définit l’API pour le comportement de la plateforme.
Créez une classe partielle native sur chaque plateforme pour laquelle votre application est conçue, et qui porte le même nom que la classe partielle multiplateforme. Cette classe partielle native doit hériter de la classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>, où
TView
est le contrôle multiplateforme auquel le comportement doit s’appliquer, etTPlatformView
est la vue native qui implémente le contrôle multiplateforme sur une plateforme particulière.Note
Bien qu’il soit nécessaire de créer une classe partielle native sur chaque plateforme pour laquelle votre application est créée, il n’est pas nécessaire d’implémenter la fonctionnalité de comportement de la plateforme sur chaque plateforme. Par exemple, vous pouvez créer un comportement de plateforme qui modifie l’épaisseur de bordure d’un contrôle natif sur certaines plateformes, mais pas toutes.
Dans chaque classe partielle native dont vous avez besoin pour implémenter le comportement de la plateforme, vous devez :
- Remplacez la méthode OnAttachedTo pour effectuer n’importe quelle configuration.
- Remplacez la méthode OnDetachedFrom pour effectuer un nettoyage.
- Implémentez les fonctionnalités principales du comportement de la plateforme.
Le comportement peut ensuite être consommé en l’attachant à la collection Behaviors du contrôle.
Définir une logique de plateforme
Pour créer un comportement de plateforme, vous devez d’abord créer une classe partielle multiplateforme qui définit l’API pour le comportement de la plateforme :
namespace BehaviorsDemos
{
public partial class TintColorBehavior
{
public static readonly BindableProperty TintColorProperty =
BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(TintColorBehavior));
public Color TintColor
{
get => (Color)GetValue(TintColorProperty);
set => SetValue(TintColorProperty, value);
}
}
}
Le comportement de la plateforme est une classe partielle dont l’implémentation est terminée sur chaque plateforme requise avec une classe partielle supplémentaire qui utilise le même nom. Dans cet exemple, la classe TintColorBehavior
définit une propriété pouvant être liée unique, TintColor
, qui teinte une image avec la couleur spécifiée.
Après avoir créé la classe partielle multiplateforme, vous devez créer une classe partielle native sur chaque plateforme pour laquelle vous générez l’application. Pour ce faire, cela peut être accompli en ajoutant des classes partielles aux dossiers enfants requis du dossier Plateformes :
Vous pouvez également configurer votre projet pour prendre en charge le multi-ciblage basé sur un nom de fichier ou le multi-ciblage basé sur des dossiers, ou les deux. Pour plus d’informations sur le multi-ciblage, consultez Configurer le multi-ciblage.
Les classes partielles natives doivent hériter de la classe PlatformBehavior<TView> ou de la classe PlatformBehavior<TView,TPlatformView>, où TView
est le contrôle multiplateforme auquel le comportement doit s’appliquer et TPlatformView
est la vue native qui implémente le contrôle multiplateforme sur une plateforme particulière. Dans chaque classe partielle native dont vous avez besoin pour implémenter le comportement de la plateforme, vous devez remplacer la méthode OnAttachedTo et la méthode OnDetachedFrom, et implémenter les fonctionnalités principales du comportement de la plateforme.
La méthode OnAttachedTo est appelée immédiatement après que le comportement de la plateforme est attaché à un contrôle multiplateforme. La méthode reçoit une référence au contrôle multiplateforme auquel elle est attachée, et éventuellement une référence au contrôle natif qui implémente le contrôle multiplateforme. La méthode peut être utilisée pour inscrire des gestionnaires d’événements ou effectuer d’autres configurations requises pour prendre en charge la fonctionnalité de comportement de la plateforme. Par exemple, vous pouvez vous abonner à un événement sur un contrôle. La fonctionnalité de comportement est ensuite implémentée dans le gestionnaire d’événements pour l’événement.
La méthode OnDetachedFrom est appelée lorsque le comportement est supprimé du contrôle multiplateforme. La méthode reçoit une référence au contrôle auquel elle est attachée, et éventuellement une référence au contrôle natif qui implémente le contrôle multiplateforme. La méthode doit être utilisée pour effectuer tout nettoyage requis. Par exemple, vous pouvez vous désabonner d’un événement sur un contrôle pour empêcher les fuites de mémoire.
Important
Les classes partielles doivent résider dans le même espace de noms et utiliser des noms identiques.
L’exemple suivant montre la TintColorBehavior
classe partielle pour Android, qui teinte une image avec une couleur spécifiée :
using Android.Graphics;
using Android.Widget;
using Microsoft.Maui.Platform;
using Color = Microsoft.Maui.Graphics.Color;
namespace BehaviorsDemos
{
public partial class TintColorBehavior : PlatformBehavior<Image, ImageView>
{
protected override void OnAttachedTo(Image bindable, ImageView platformView)
{
base.OnAttachedTo(bindable, platformView);
if (bindable is null)
return;
if (TintColor is null)
ClearColor(platformView);
else
ApplyColor(platformView, TintColor);
}
protected override void OnDetachedFrom(Image bindable, ImageView platformView)
{
base.OnDetachedFrom(bindable, platformView);
if (bindable is null)
return;
ClearColor(platformView);
}
void ApplyColor(ImageView imageView, Color color)
{
imageView.SetColorFilter(new PorterDuffColorFilter(color.ToPlatform(), PorterDuff.Mode.SrcIn ?? throw new NullReferenceException()));
}
void ClearColor(ImageView imageView)
{
imageView.ClearColorFilter();
}
}
}
Dans cet exemple, la classe TintColorBehavior
dérive de la classe PlatformBehavior<TView,TPlatformView>, où TView
est un Image et TPlatformView
est un ImageView. La OnAttachedTo applique la couleur de teinte à l’image, à condition que la propriété TintColor
ait une valeur. La méthode OnDetachedFrom supprime la couleur de teinte de l’image.
Une classe partielle native doit être ajoutée sur chaque plateforme pour laquelle vous générez votre application. Toutefois, vous pouvez rendre la classe partielle native sans opération, si le comportement spécifique à la plateforme n’est pas nécessaire sur une certaine plateforme. Pour ce faire, fournissez une classe vide :
using Microsoft.UI.Xaml;
namespace BehaviorsDemos
{
public partial class TintColorBehavior : PlatformBehavior<Image, FrameworkElement>
{
// NO-OP on Windows
}
}
Important
.NET MAUI ne définit pas la BindingContext
d’un comportement de plateforme.
Consommer un comportement de plateforme
Chaque contrôle .NET MAUI a une collection de Behaviors, auquel un ou plusieurs comportements de plateforme peuvent être ajoutés :
<Image Source="dotnet_bot.png"
HeightRequest="200"
HorizontalOptions="Center">
<Image.Behaviors>
<local:TintColorBehavior TintColor="Red" />
</Image.Behaviors>
</Image>
L'Image équivalent en C# est illustré dans l’exemple suivant :
Image image = new Image { Source = "dotnet_bot.png", HeightRequest = 200, HorizontalOptions = LayoutOptions.Center };
image.Behaviors.Add(new TintColorBehavior());
La capture d’écran suivante montre le comportement de la plateforme qui teinte une image :
Avertissement
Les comportements de plateforme sont écrits pour un type de contrôle spécifique (ou une superclasse qui peut s’appliquer à de nombreux contrôles), et ils ne doivent être ajoutés qu’à un contrôle compatible. Toute tentative d’attachement d’un comportement de plateforme à un contrôle incompatible entraîne la levée d’une exception.