Créer une interface utilisateur cohérente à l’aide de styles

Effectué

Les ressources sont idéales pour éviter les valeurs codées en dur et en double dans votre balisage XAML, mais elles peuvent être fastidieuses à appliquer. Vous attribuez une valeur à chaque propriété individuellement, ce qui peut produire un XAML fouillis et difficile à lire. Cette unité vous montre comment regrouper plusieurs paramètres dans un style, ce qui peut vous aider à épurer votre code et à le rendre plus gérable.

Comment les ressources peuvent encombrer votre XAML

Une ressource fournit une valeur pour une seule propriété. Toutefois, l’utilisation de nombreuses ressources peut entraîner un XAML fouillis. Supposons que vous souhaitez personnaliser l’apparence des boutons de votre application. Vous devez tout d’abord créer les ressources correspondant aux valeurs souhaitées. Ensuite, vous appliquez chaque ressource à tous les boutons. Le code suivant montre à quoi peut ressembler le balisage XAML pour deux boutons.

<Button
    Text = "OK"
    BackgroundColor = "{StaticResource highlightColor}"
    BorderColor = "{StaticResource borderColor}"
    BorderWidth = "{StaticResource borderWidth}"
    TextColor = "{StaticResource textColor}" />

<Button
    Text = "Cancel"
    BackgroundColor = "{StaticResource highlightColor}"
    BorderColor = "{StaticResource borderColor}"
    BorderWidth = "{StaticResource borderWidth}"
    TextColor = "{StaticResource textColor}" />

Comme le montre cet exemple, les cinq mêmes propriétés sont définies sur chaque bouton. L’utilisation des ressources supprime le besoin de valeurs répétées et codées en dur dans quatre d’entre elles. Toutefois, ce type de balisage XAML risque rapidement de devenir difficile à lire. De plus, si vous définissez un grand nombre de propriétés pour chaque contrôle, il est facile d’oublier accidentellement l’une d’elles, ce qui entraîne des incohérences dans l’apparence des contrôles. La solution est de créer un style qui attribue les quatre propriétés à la fois.

Qu’est-ce qu’un setter ?

Les setters sont les composants clés que vous utilisez pour créer des styles.

Un setter est un conteneur renfermant une paire propriété-valeur. Un setter peut être vu comme la représentation d’une instruction d’assignation. Vous spécifiez la propriété à assigner et la valeur à appliquer. Normalement, vous créez des objets Setter dans votre balisage XAML. L’exemple suivant crée un objet Setter pour la propriété TextColor.

<Setter Property="TextColor" Value="White" />

Vous pouvez utiliser une ressource pour la valeur dans un setter comme cela est montré dans le code suivant. Cette technique est pratique si vous voulez utiliser la même valeur dans plusieurs setters.

<Setter Property="TextColor" Value="{StaticResource textColor}" />

Notes

La valeur de propriété que vous spécifiez dans un setter doit être implémentée en tant que propriété liable. Toutes les propriétés des contrôles dans .NET MAUI qui se terminent par le suffixe Property sont des propriétés liables. Si vous essayez d’utiliser une propriété telle que TextColor dans un setter, vérifiez qu’il existe une propriété liable correspondante appelée TextColorProperty pour ce contrôle. En pratique, quasiment toutes les propriétés dont vous aurez besoin dans vos setters seront implémentées de cette façon.

Qu’est-ce qu’un style ?

Un style est une collection de setters ciblant un type spécifique de contrôle. .NET MAUI a besoin d’un type cible pour s’assurer que les propriétés de vos setters existent pour ce type.

Le code suivant montre un style qui combine les quatre valeurs de l’exemple précédent. Notez que TargetType est défini sur Button et que toutes les propriétés des setters sont membres de la classe Button. Vous ne pouvez pas utiliser ce style pour une étiquette, car la classe Label n’inclut pas la propriété BorderColor ou BorderWidth.

<Style TargetType="Button">
    <Setter Property="BackgroundColor" Value="#2A84D3" />
    <Setter Property="BorderColor" Value="#1C5F9B" />
    <Setter Property="BorderWidth" Value="3" />
    <Setter Property="TextColor" Value="White" />
</Style>

Définir un style

Normalement, vous définissez des styles en tant que ressources au sein d’un objet ResourceDictionary. Un dictionnaire de ressources facilite l’utilisation du style dans plusieurs contrôles d’une même page ou même dans toute votre application. Le code suivant montre comment définir un style en tant que ressource dans un dictionnaire. Notez que le style reçoit un nom à l’aide de la propriété x:Key. Le nommage d’un style vous permet de le référencer à partir de vos pages XAML.

<ContentPage.Resources>
    <Style x:Key="MyButtonStyle" TargetType="Button">
        ...
    </Style>
</ContentPage.Resources>

Appliquer un style

Vous attachez un style à un contrôle en affectant le nom à la propriété Style. Par cette action, vous appliquez chacun des objets Setter du style au contrôle cible. Le code suivant montre comment appliquer un style de bouton à deux boutons.

<Button Text="OK" Style="{StaticResource MyButtonStyle}" />
<Button Text="Cancel" Style="{StaticResource MyButtonStyle}" />

Dans l’exemple précédent, vous avez utilisé l’extension de balisage StaticResource pour attacher le style aux contrôles. Cette technique est pratique quand vous n’avez pas besoin de changer le style au moment de l’exécution. Et si vous voulez implémenter des thèmes dynamiques, où l’interface utilisateur doit-elle changer ? Dans ce cas, vous pouvez utiliser l’extension de balisage DynamicResource pour charger le style.

<Button Text="Cancel" Style="{DynamicResource MyButtonStyle}" />

DynamicResource écoute le remplacement de la propriété x:Key dans le dictionnaire de ressources. Si vous écrivez du code qui charge un nouveau style dans ResourceDictionary avec cette même valeur x:key, le nouveau style est automatiquement appliqué à votre interface utilisateur.

Utiliser un style implicite pour plusieurs contrôles

Supposons que votre interface utilisateur comporte 50 boutons auxquels vous souhaitez appliquer le même style. D’après ce que nous avons vu jusqu’à présent, vous devez attribuer la propriété Style à chaque bouton manuellement. Ce n’est pas très difficile à faire, mais cela reste fastidieux.

Un style implicite est un style que vous ajoutez à un dictionnaire de ressources sans lui donner d’identificateur x:Key. Les styles implicites sont automatiquement appliqués à tous les contrôles de l’objet TargetType spécifié.

Le code suivant montre l’exemple précédent déclaré en tant que style implicite. Ce style est appliqué à chaque bouton sur la page.

<ContentPage.Resources>
    <Style TargetType="Button">
        <Setter Property="BackgroundColor" Value="Blue" />
        <Setter Property="BorderColor" Value="Navy" />
        ...
    </Style>
</ContentPage.Resources>

Important

Les styles implicites appliqués aux contrôles nécessitent une correspondance exacte avec le TargetType spécifié. Les contrôles qui héritent du type cible ne recevront pas les styles. Pour affecter les contrôles hérités, vous pouvez définir l’attribut Style.ApplyToDerivedTypes sur True lorsque vous définissez le style. Par exemple, pour appliquer un style au type Button et l’affecter à l’un de vos boutons qui héritent de Button (par exemple, ImageButton, RadioButton ou un type personnalisé que vous créez), vous pouvez utiliser un style comme celui-ci.

<ContentPage.Resources>
    <Style TargetType="Button"
           ApplyToDerivedTypes="True">
        <Setter Property="BackgroundColor" Value="Black" />
    </Style>
</ContentPage.Resources>

Remplacer un style

Vous pouvez penser à un style comme quelque chose qui fournit un ensemble de valeurs par défaut pour des contrôles. Un style existant peut être proche de vos exigences, mais contenir un ou deux setters que vous ne souhaitez pas. Dans ce cas, vous pouvez appliquer le style, puis remplacer la valeur en paramétrant directement les propriétés. Le paramètre explicite est appliqué après le style ; il substitue donc la valeur existante dans le style.

Supposons que vous souhaitez utiliser le style suivant pour plusieurs boutons de votre page.

<Style x:Key="MyButtonStyle" TargetType="Button">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="BorderRadius" Value="10" />
    <Setter Property="BorderWidth" Value="3" />
</Style>

Ce style convient pour tous les boutons, à l’exception de Cancel qui doit avoir un arrière-plan rouge. Vous pouvez utiliser le même style pour le bouton Cancel à condition de définir aussi la propriété BackgroundColor directement. Le code suivant montre comment substituer le paramètre de la couleur.

<Button
    Text="Cancel"
    Style="{StaticResource MyButtonStyle}"
    BackgroundColor="Red"
    ... />

Cibler un type ancêtre

Imaginons que vous voulez appliquer une couleur d’arrière-plan personnalisée à vos boutons et étiquettes. Vous pouvez créer des styles distincts pour chaque type, ou vous pouvez créer un style avec TargetType défini sur VisualElement. Cette technique fonctionne parce que VisualElement est une classe de base pour Button et Label.

Le code suivant montre un style qui cible une classe de base appliquée à deux types dérivés différents.

<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
    <Setter Property="BackgroundColor" Value="#2A84D3" />
</Style>
...
<Button Style="{StaticResource MyVisualElementStyle}" ... />
<Label Style="{StaticResource MyVisualElementStyle}" ... />

Cet exemple identifie le style à l’aide de x:Key et les contrôles l’appliquent explicitement. L’utilisation d’un style implicite n’est pas possible ici, car le TargetType d’un style implicite doit correspondre exactement au type du contrôle.

Utiliser BasedOn pour hériter un style

Supposons que vous souhaitez apporter de la cohérence à l’interface utilisateur de votre application. Vous décidez d’utiliser la même couleur d’arrière-plan pour tous les contrôles. Le paramètre de couleur d’arrière-plan est susceptible d’apparaître dans plusieurs de vos styles. Le code suivant montre deux styles avec un setter répété plusieurs fois.

<Style x:Key="MyButtonStyle" TargetType="Button">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="BorderColor" Value="Navy" />
    <Setter Property="BorderWidth" Value="5" />
</Style>

<Style x:Key="MyEntryStyle" TargetType="Entry">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="TextColor" Value="White" />
</Style>

Vous pouvez utiliser l’héritage de style pour factoriser le setter dupliqué en style de base. Pour créer un style dérivé, définissez sa propriété BasedOn pour référencer le style de base. Le nouveau style hérite de tous les setters de son style de base. Le style dérivé peut également ajouter de nouveaux setters ou remplacer un setter hérité par un autre qui contient une valeur différente.

Le code suivant montre l’exemple précédent avec les styles refactorisés en hiérarchie. Le setter commun est présent dans le style de base uniquement au lieu d’être répété. Notez que vous utilisez l’extension de balisage StaticResource pour rechercher le style de base. Vous ne pouvez pas utiliser DynamicResource dans cette situation.

<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
    <Setter Property="BackgroundColor" Value="Blue" />
</Style>

<Style x:Key="MyButtonStyle" TargetType="Button" BasedOn="{StaticResource MyVisualElementStyle}">
    <Setter Property="BorderColor" Value="Navy" />
    <Setter Property="BorderWidth" Value="5" />
</Style>

<Style x:Key="MyEntryStyle" TargetType="Entry" BasedOn="{StaticResource MyVisualElementStyle}">
    <Setter Property="TextColor" Value="White" />
</Style>

La valeur TargetType du style de base et du style dérivé doit être compatible. Pour que les styles soient compatibles, ils doivent avoir la même propriété TargetType, ou le TargetType du style dérivé est un descendant du TargetType du style de base.

Contrôle des connaissances

1.

Pourquoi définiriez-vous un style dans un ResourceDictionary ?