« Style » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
 
 
(4 versions intermédiaires par le même utilisateur non affichées)
Ligne 34 : Ligne 34 :


= Héritage de style: BasedOn =
= Héritage de style: BasedOn =
Quand on définit le Style d'un Control, on écrase le Style précédemment définit:
{{boxx|BasedOn}} permet d'hériter d'un autre style afin de l'enrichir.
<kode lang="xaml">
<kode lang="xaml">
<xxx.Resources>
<xxx.Resources>
     <!-- On définit un style par défaut qui va s'appliquer à tous les boutons -->
     <!-- On hérite du style par défaut des boutons -->
     <Style TargetType="Button">
     <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
         <Setter Property="Background" Value="Cyan"/>
        <Setter Property="Background" Value="Blue" />
    </Style>
 
    <!-- On hérite du style CustomButtonStyle -->
    <Style TargetType="Button" BasedOn="{StaticResource CustomButtonStyle}">
         <Setter Property="Background" Value="Blue" />
     </Style>
     </Style>
</xxx.Resources>
</xxx.Resources>
<!-- Ce bouton a bien son Background à Cyan -->
<Button Content="Button1" />
<!-- Ici on redéfinit le style pour changer le Foreground -->
<!-- Le style par défaut étant écrasé le Background est gris (style du système) -->
<Button Content="Button2">
    <Button.Style>
        <Style TargetType="Button" >
            <Setter Property="Foreground" Value="Beige"/>
        </Style>
    </Button.Style>
</Button>
</kode>
La solution est d'hériter du Style par défaut:
<kode lang="xaml">
<Button Content="Button2">
    <Button.Style>
        <Style TargetType="Button" BasedOn="{StaticResource ResourceKey={x:Type Button}}">
            <Setter Property="Foreground" Value="Beige"/>
        </Style>
    </Button.Style>
</Button>
</kode>
</kode>



Dernière version du 19 octobre 2021 à 21:28

Définition

Permet de changer les valeurs des propriétés des objets graphiques.
Équivalent du CSS pour WPF.

Une fois appliqué, un style ne peut être modifié (propriété IsSealed).

Syntaxe

Depuis les ressources

Xaml.svg
<Window.Resources>
    <!-- Style implicite (sans key), s'applique à toutes les types TextBox -->
    <Style TargetType="TextBox">
        <Setter Property="Background" Value="Cyan" />
    </Style>
    <!-- Change la propriété Background des TextBox qui utilisent explicitement ce style -->
    <Style x:Key="tbxStyle1" TargetType="TextBox">
        <Setter Property="Background" Value="Red" />
    </Style>
</Window.Resources>

<TextBox Style="{StaticResource tbxStyle1}"></TextBox>

Directement dans le Control

Xaml.svg
<ComboBox SelectedIndex="0">
    <ComboBox.Style>
        <Style TargetType="ComboBox">
            <Setter Property="Background" Value="Cyan" />
        </Style>
    </ComboBox.Style>
</ComboBox>

Héritage de style: BasedOn

BasedOn permet d'hériter d'un autre style afin de l'enrichir.

Xaml.svg
<xxx.Resources>
    <!-- On hérite du style par défaut des boutons -->
    <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
        <Setter Property="Background" Value="Blue" />
    </Style>

    <!-- On hérite du style CustomButtonStyle -->
    <Style TargetType="Button" BasedOn="{StaticResource CustomButtonStyle}">
        <Setter Property="Background" Value="Blue" />
    </Style>
</xxx.Resources>

BasedOn et DynamicResource

On utilise donc StaticResource pour hériter du style par défaut. Mais StaticResource contraint la ressource à se trouver définie dans le dictionnaire de ressources.
Ce n'est pas toujours le cas par exemple si une application définit son thème par défaut dans App.xaml et utilise des Control importés depuis d'autres assemblages. Ces Control n'auront pas d'accès "statique" au style par défaut, et l'héritage ne se fait pas.
La solution serait d'utiliser un lien "dynamique" mais BasedOn ne supporte pas DynamiqueResource.
Il faut donc créer son propre MarkupExtension:

Csharp.svg
[MarkupExtensionReturnType(typeof(object))]
public class StaticApplicationResource : MarkupExtension
{
    public StaticApplicationResource(object resourceKey)
    {
        ResourceKey = resourceKey;
    }

    [ConstructorArgument("resourceKey")]
    public object ResourceKey { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (ResourceKey == null)
            return null;

        // On cherche dans App.xaml (et pas ailleurs) si on trouve la ressource.
        return System.Windows.Application.Current.TryFindResource(ResourceKey);
    }
}
Xaml.svg
<Button Content="Button2">
    <Button.Style>
        <Style TargetType="Button" BasedOn="{my:StaticApplicationResource {x:Type Button}}"">
            <Setter Property="Foreground" Value="Beige"/>
        </Style>
    </Button.Style>
</Button>

Ordre de résolution entre les Style

Style order.png

Valeur par défaut

Csharp.svg
public static readonly DependencyProperty MyValueProperty =
    DependencyProperty.Register("MyValue", typeof(string), typeof(MyCustomControl), new UIPropertyMetadata("Valeur par défaut"));

Héritage

Xaml.svg
<Grid local:MyCustomControl.MyValue="Héritage">
    <local:MyCustomControl />
</Grid>

Style par défaut

Xaml.svg
<Style TargetType="{x:Type local:MyCustomControl}">
    <Setter Property="MyValue" Value="Style par défaut" />

Style setters

Xaml.svg
<local:MyCustomControl>
    <local:MyCustomControl.Style>
        <Style TargetType="local:MyCustomControl">
            <Setter Property="MyValue" Value="Style setters" />

Template triggers

Xaml.svg
<local:MyCustomControl>
    <local:MyCustomControl.Template>
        <ControlTemplate TargetType="local:MyCustomControl">
            <ControlTemplate.Triggers>
                <Trigger Property="IsEnabled" Value="True">
                    <Setter Property="MyValue" Value="Template triggers" />

Style triggers

Xaml.svg
<local:MyCustomControl>
    <local:MyCustomControl.Style>
        <Style TargetType="local:MyCustomControl">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />

Style implicite

Dans un dictionnaire de ressources, style sans clé qui s'applique à tous les TargetType.

Xaml.svg
<!-- style sans clé qui s'applique à tous les TextBlock -->
<Style TargetType="{x:Type TextBlock}">
    <Setter Property="Foreground" Value="Blue" />
</Style>
La clé est en fait le TargetType.

TemplatedParent template properties

Xaml.svg
<ContentControl x:Name="contentControl">
    <ContentControl.Template>
        <ControlTemplate TargetType="ContentControl">
            <local:MyCustomControl MyValue="TemplatedParent template properties" x:Name="myCustomControl">

Valeur locale

Csharp.svg
myCustomControl.MyValue = "Valeur locale";

Animation