Partager via


Application d'un style et création de modèles

L'application d'un style et la création de modèles Windows Presentation Foundation (WPF) fait référence à une suite de fonctionnalités (styles, modèles, déclencheurs et storyboards) qui permettent aux développeurs et aux concepteurs de créer des effets visuellement attrayants et une apparence cohérente pour leur produit. Bien que les développeurs et ou les concepteurs peuvent largement personnaliser l'apparence sur une base application-par-application, un modèle d'application de style et de création de modèles est nécessaire pour permettre la maintenance et le partage de l'apparence dans et entre des applications. Windows Presentation Foundation (WPF) fournit ce modèle.

Une autre fonction du modèle de style WPF consiste en la séparation de la présentation et de la logique. Cela signifie que les concepteurs peuvent travailler sur l'apparence d'une application en utilisant uniquement XAML pendant que les développeurs travaillent sur la programmation logique à l'aide de C# ou Visual Basic.

Cette vue d'ensemble s'intéresse principalement aux aspects de l'application liés à la définition d'un style et à la création de modèles, et n'aborde pas du tout la liaison de données. Pour plus d'informations sur la liaison de données, consultez Vue d'ensemble de la liaison de données.

En outre, il est important de comprendre ce que sont les ressources, puisque ce sont elles qui permettent la réutilisation des styles et des modèles. Pour plus d'informations sur les ressources, consultez Vue d'ensemble des ressources.

Cette rubrique comprend les sections suivantes.

  • Exemple d'application d'un style et de création de modèles
  • Notions de base relatives aux styles
  • Modèles de données
  • Modèles de contrôle
  • Déclencheurs
  • Ressources partagées et thèmes
  • Rubriques connexes

Exemple d'application d'un style et de création de modèles

Les exemples de code utilisés dans cette vue d'ensemble sont basés sur un exemple de photo simple affiché dans l'illustration suivante :

Vue de la liste mise en forme avec des styles

Cet exemple de photo simple utilise l'application d'un style et la création de modèles pour créer une expérience utilisateur visuellement attrayante. L'exemple est composé de deux éléments TextBlock et d'un contrôle ListBox lié à une liste d'images. Pour obtenir l'exemple complet, consultez Introduction aux styles et aux modèles, exemple.

Notions de base relatives aux styles

Vous pouvez considérer un Style comme un moyen pratique d'appliquer un ensemble de valeurs de propriétés à plusieurs éléments. Par exemple, considérez les éléments TextBlock suivants et leur apparence par défaut :

<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>

Capture d'écran : exemple de styles

Vous pouvez modifier l'apparence par défaut en définissant des propriétés, telles que FontSize et FontFamily, sur chaque élément TextBlock directement. Toutefois, si vous souhaitez que vos éléments TextBlock partagent quelques propriétés, vous pouvez créer un Style dans la section Resources de votre fichier XAML, comme illustré ici :

<Window.Resources>


...


<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
  <Setter Property="HorizontalAlignment" Value="Center" />
  <Setter Property="FontFamily" Value="Comic Sans MS"/>
  <Setter Property="FontSize" Value="14"/>
</Style>


...


</Window.Resources>

Lorsque vous affectez au TargetType de votre style le type TextBlock, ce style est appliqué à tous les éléments TextBlock qui se trouvent dans la fenêtre.

Les éléments TextBlock apparaissent désormais comme suit :

Capture d'écran : exemple de styles

Extension de styles

Il est possible que vous souhaitiez que vos deux éléments TextBlock partagent quelques valeurs de propriété, telles que le FontFamily et le HorizontalAlignment centré, mais vous pouvez également souhaiter que le texte "Mes images" ait quelques propriétés supplémentaires. Pour ce faire, vous pouvez créer un style sur la base du premier style, comme illustré ici :

<Window.Resources>


...


<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
       TargetType="TextBlock"
       x:Key="TitleText">
  <Setter Property="FontSize" Value="26"/>
  <Setter Property="Foreground">
  <Setter.Value>
      <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Offset="0.0" Color="#90DDDD" />
          <GradientStop Offset="1.0" Color="#5BFFFF" />
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
</Style>


...


</Window.Resources>

Remarquez qu'au style précédent est attribué un x:Key. Pour appliquer le style, vous affectez la valeur x:Key à la propriété Style dans votre TextBlock, comme illustré ici :

<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>

La propriété HorizontalAlignment de ce style TextBlock a désormais la valeur Center ; la propriété FontFamily a la valeur Comic Sans MS ; la propriété FontSize a la valeur 26 ; et enfin, la propriété Foreground a la valeur LinearGradientBrush indiquée dans l'exemple. Remarquez qu'elle substitue la valeur FontSize du style de base. Si plusieurs Setter définissent la même propriété dans un Style, le dernier Setter déclaré prime.

Voici à présent comment se présentent les éléments TextBlock :

TextBlocks mis en forme avec des styles

Ce style TitleText étend le style créé pour le type TextBlock. Vous pouvez également étendre un style qui a un x:Key en utilisant la valeur x:Key. Consultez l'exemple indiqué pour le BasedOn.

Relation de la propriété TargetType et de l'attribut x:Key

Comme indiqué dans le premier exemple, affecter à la propriété TargetType la valeur TextBlock sans assigner un x:Key au style entraîne l'application du style à tous les éléments TextBlock. Dans ce cas, x:Key a implicitement la valeur {x:Type TextBlock}. En d'autres termes, si vous affectez explicitement à x:Key une valeur autre que {x:Type TextBlock}, le Style n'est pas appliqué automatiquement à tous les éléments TextBlock. Au lieu de cela, vous devez appliquer explicitement le style (en utilisant la valeur x:Key) aux éléments TextBlock. Si votre style se trouve dans la section des ressources et vous ne définissez pas la propriété TargetType dans votre style, vous devez alors indiquer un x:Key.

Outre l'indication d'une valeur par défaut pour x:Key, la propriété TargetType spécifie le type auquel s'appliquent les propriétés d'accesseur Set. Si vous ne spécifiez pas de TargetType, vous devez qualifier les propriétés dans vos objets Setter avec un nom de classe à l'aide de la syntaxe Property="ClassName.Property". Par exemple, au lieu de définir Property="FontSize", vous devez affecter à Property la valeur "TextBlock.FontSize" ou "Control.FontSize".

Notez également que de nombreux contrôles WPF consistent en une combinaison d'autres contrôles WPF. Si vous créez un style qui s'applique à tous les contrôles d'un type, vous risquez d'obtenir des résultats inattendus. Par exemple, si vous créez un style qui cible le type TextBlock dans une Window, le style est appliqué à tous les contrôles TextBlock de la fenêtre, même si le TextBlock fait partie d'un autre contrôle, tel qu'un ListBox.

Styles et ressources

Vous pouvez utiliser un style sur tout élément dérivé de FrameworkElement ou FrameworkContentElement. La méthode la plus courante pour déclarer un style consiste à le faire en tant que ressource dans la section Resources d'un fichier XAML, comme indiqué dans les exemples précédents. Les styles étant des ressources, ils obéissent aux mêmes règles de portée qui s'appliquent à toutes les ressources ; ainsi, l'emplacement où est déclaré un style affecte l'emplacement où un style peut s'appliquer. Si, par exemple, vous déclarez le style dans l'élément racine de votre fichier de définition d'application XAML, le style peut être utilisé n'importe où dans votre application. Si vous créez une application de navigation et déclarez le style dans l'un de ses fichiers XAML, ce style ne pourra être utilisé que dans ce fichier XAML. Pour plus d'informations sur les règles de portée relatives aux ressources, consultez Vue d'ensemble des ressources.

De plus, un complément d'informations sur les styles et les ressources est disponible dans la section Ressources et thèmes partagés plus loin dans cette vue d'ensemble.

Définition de styles par programmation

Pour assigner par programmation un style nommé à un élément, obtenez le style de la collection de ressources et assignez-le à la propriété Style de l'élément. Notez que les éléments dans une collection de ressources sont de type Object. Par conséquent, vous devez effectuer un cast du style extrait en un Style avant de l'assigner à la propriété Style. Par exemple, pour définir le style TitleText défini sur un TextBlock nommé textblock1, procédez comme suit :

textblock1.Style = CType(Me.Resources("TitleText"), Style)
textblock1.Style = (Style)(this.Resources["TitleText"]);

Notez qu'une fois qu'un style a été appliqué, il est scellé et ne peut plus être modifié. Si vous souhaitez modifier dynamiquement un style qui a déjà été appliqué, vous devez créer un style pour remplacer ce dernier. Pour plus d'informations, consultez la propriété IsSealed.

Vous pouvez créer un objet qui choisit un style à appliquer selon une logique personnalisée. Consultez l'exemple indiqué pour la classe StyleSelector.

Liaisons, ressources dynamiques et gestionnaires d'événements

Notez que vous pouvez utiliser la propriété Setter.Value pour spécifier un Binding, extension de balisage ou un DynamicResource, extension de balisage. Pour plus d'informations, consultez les exemples fournis pour la propriété Setter.Value.

Jusqu'à présent, cette vue d'ensemble traite seulement l'utilisation de méthodes setter pour définir la valeur de propriété. Vous pouvez également spécifier des gestionnaires d'événements dans un style. Pour plus d'informations, consultez EventSetter.

Modèles de données

Il existe dans cet exemple d'application, un contrôle ListBox lié à une liste de photos :

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
         Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>

Ce ListBox se présente actuellement comme suit :

ListBox avant application du modèle

La plupart des contrôles ont quelque type de contenu, et ce contenu vient souvent des données avec lesquelles vous créez une liaison. Dans cet exemple, les données correspondent à la liste de photos. Dans WPF, vous utilisez un DataTemplate pour définir la représentation visuelle des données. Fondamentalement, le contenu que vous placez dans un DataTemplate détermine l'apparence des données dans l'application rendue.

Dans notre exemple d'application, chaque objet Photo personnalisé a une propriété Source de chaîne de type qui spécifie le chemin d'accès du fichier de l'image. Actuellement, les objets photo apparaissent comme des chemins d'accès de fichiers.

Pour que les photos apparaissent comme des images, vous créez un DataTemplate comme une ressource :

<Window.Resources>


...


<!--DataTemplate to display Photos as images
    instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
  <Border Margin="3">
    <Image Source="{Binding Source}"/>
  </Border>
</DataTemplate>


...


</Window.Resources>

Notez que la propriété DataType est très similaire à la propriété TargetType du Style. Si votre DataTemplate est dans la section de ressources, lorsque vous spécifiez la propriété DataType à un type et ne lui assignez pas de x:Key, le DataTemplate est appliqué chaque fois que ce type apparaît. Vous avez toujours la possibilité d'assigner le DataTemplate avec un x:Key, puis de le définir comme un StaticResource pour les propriétés qui prennent les types DataTemplate, comme la propriété ItemTemplate ou ContentTemplate.

Le DataTemplate indiqué dans l'exemple ci-dessus définit essentiellement que chaque fois qu'il existe un objet Photo, celui-ci doit apparaître comme un Image dans un Border. Avec ce DataTemplate, notre application se présente maintenant comme suit :

Image photo

Le modèle de création de modèles fournit d'autres fonctions. Par exemple, si vous affichez les données d'une collection contenant d'autres collections à l'aide d'un type HeaderedItemsControl tel qu'un Menu ou un TreeView, le HierarchicalDataTemplate existe. Une autre fonction de création de modèles de données est le DataTemplateSelector, qui permet de choisir le DataTemplate à utiliser selon la logique personnalisée. Pour plus d'informations, consultez Vue d'ensemble des modèles de données, qui décrit plus en détail les différentes fonctions de création de modèles de données.

Modèles de contrôle

Dans WPF, le ControlTemplate d'un contrôle définit l'apparence de ce dernier. Vous pouvez modifier la structure et l'apparence d'un contrôle en définissant pour ce dernier un nouveau ControlTemplate. Dans de nombreux cas, vous avez suffisamment de flexibilité et vous n'avez pas à écrire vos propres contrôles personnalisés. Pour plus d'informations, consultez Personnalisation de l'apparence d'un contrôle existant en créant un ControlTemplate.

Déclencheurs

Un déclencheur définit des propriétés ou démarre des actions, telles qu'une animation, lorsqu'une valeur de propriété change ou lorsqu'un événement est déclenché. Style, ControlTemplate et DataTemplate ont tous une propriété Triggers qui peut contenir un jeu de déclencheurs. Il existe différents types de déclencheurs.

Déclencheurs de propriété

Un Trigger qui définit des valeurs de propriété ou démarre des actions selon la valeur d'une propriété est appelé un déclencheur de propriété.

Pour montrer comment utiliser des déclencheurs de propriété, vous pouvez rendre chaque ListBoxItem partiellement transparent à moins qu'il ne soit sélectionné. Le style suivant affecte à la propriété Opacity d'un ListBoxItem la valeur 0.5. Toutefois, lorsque la propriété IsSelected a la valeur true, Opacity a la valeur 1.0 :

<Style TargetType="ListBoxItem">
  <Setter Property="Opacity" Value="0.5" />
  <Setter Property="MaxHeight" Value="75" />
  <Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
        <Setter Property="Opacity" Value="1.0" />
    </Trigger>


...


  </Style.Triggers>
</Style>

Cet exemple utilise un Trigger pour définir une valeur de propriété, mais notez que la classe Trigger a également les propriétés EnterActions et ExitActions qui permettent à un déclencheur d'exécuter des actions.

Notez que la propriété MaxHeight de ListBoxItem a la valeur 75. Dans l'illustration suivante, le troisième élément est l'élément sélectionné :

Vue de la liste mise en forme avec des styles

EventTriggers et tables de montage séquentiel

Un autre type de déclencheur est le EventTrigger, qui lance un jeu d'actions en fonction de l'occurrence d'un événement. Par exemple, les objets EventTrigger suivants spécifient que lorsque le pointeur de la souris entre dans le ListBoxItem, la propriété MaxHeight s'anime sur une valeur de 90 pendant une période de 0.2 seconde. Lorsque la souris s'éloigne de l'élément, la propriété retrouve sa valeur initiale sur une période de 1 seconde. Notez qu'il n'est pas nécessaire de spécifier une valeur To pour l'animation MouseLeave. Et ce car l'animation est capable d'effectuer le suivi de la valeur initiale.

        <EventTrigger RoutedEvent="Mouse.MouseEnter">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Duration="0:0:0.2"
                  Storyboard.TargetProperty="MaxHeight"
                  To="90"  />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseLeave">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Duration="0:0:1"
                  Storyboard.TargetProperty="MaxHeight"  />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>

Pour plus d'informations, consultez Vue d'ensemble des storyboards.

Dans l'illustration suivante, la souris pointe sur le troisième élément :

Capture d'écran : exemple de styles

MultiTriggers, DataTriggers et MultiDataTriggers

Outre Trigger et EventTrigger, il existe d'autres types de déclencheurs : MultiTrigger vous permet de définir les valeurs des propriétés selon plusieurs conditions. Vous utilisez DataTrigger et MultiDataTrigger lorsque la propriété de votre condition est liée aux données.

Ressources partagées et thèmes

Une application Windows Presentation Foundation (WPF) typique peut avoir plusieurs ressources d'interface utilisateur appliquées partout dans l'application. Collectivement, cet ensemble de ressources peut être considéré comme le thème pour l'application. Windows Presentation Foundation (WPF) fournit du support pour empaqueter des ressources d'interface utilisateur en tant que thème à l'aide d'un dictionnaire de ressources encapsulé en tant que classe ResourceDictionary.

Les thèmes Windows Presentation Foundation (WPF) sont définis en utilisant le mécanisme d'application d'un style et de création de modèles que Windows Presentation Foundation (WPF) expose pour la personnalisation des visuels de tout élément.

Les ressources du thème Windows Presentation Foundation (WPF) sont stockées dans les dictionnaires de ressources incorporés. Ces dictionnaires de ressources doivent être incorporés dans un assembly signé et ils peuvent être incorporés dans le même assembly que le code proprement dit ou dans un assembly côte à côte. Dans le cas de PresentationFramework.dll, l'assembly contenant des contrôles Windows Presentation Foundation (WPF), les ressources du thème se trouvent dans une série d'assemblys côte à côte.

Le thème devient la dernière place à consulter lors de la recherche du style d'un élément. La recherche commencera généralement en remontant l'arborescence des éléments, à la recherche d'une ressource appropriée, puis en parcourant la collection des ressources de l'application et enfin en interrogeant le système. Cela donne aux développeurs d'applications une chance de redéfinir le style pour tout objet au niveau de l'arborescence ou au niveau de l'application avant d'atteindre le thème.

Vous pouvez définir des dictionnaires de ressources comme des fichiers individuels qui vous permettent de réutiliser un thème entre plusieurs applications. Vous pouvez également créer des thèmes permutables en définissant plusieurs dictionnaires de ressources qui fournissent les mêmes types de ressources mais avec des valeurs différentes. Il est recommandé de redéfinir ces styles ou d'autres ressources au niveau de l'application pour définir l'apparence d'une application.

Pour partager un jeu de ressources, y compris styles et modèles, entre les applications, vous pouvez créer un fichier XAML et définir un ResourceDictionary. Par exemple, jetez un coup d'œil sur l'illustration suivante qui montre une partie du Style avec ControlTemplates, exemple:

Exemples de modèle de contrôle

Si vous parcourez les fichiers XAML indiqués dans l'exemple, vous observerez que tous ont les éléments suivants :

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>

C'est le partage de shared.xaml, qui définit un ResourceDictionary contenant un jeu de styles et de ressources de pinceau permettant de définir une apparence homogène des contrôles illustrés dans l'exemple.

Pour plus d'informations, consultez Dictionnaires de ressources fusionnés.

Si vous créez un thème pour votre contrôle personnalisé, consultez la section Bibliothèque de contrôles externes de Vue d'ensemble de la création de contrôles.

Voir aussi

Tâches

Rechercher des éléments générés par ControlTemplate

Comment : rechercher des éléments générés par DataTemplate

Concepts

URI à en-tête pack dans WPF