Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Avec Windows Presentation Foundation (WPF), vous pouvez personnaliser la structure visuelle et le comportement d’un contrôle existant avec votre propre modèle réutilisable. Les modèles peuvent être appliqués globalement à votre application, fenêtres et pages, ou directement aux contrôles. La plupart des scénarios qui vous obligent à créer un contrôle peuvent être couverts par la création d’un modèle pour un contrôle existant.
Dans cet article, vous allez explorer la création d’un nouveau ControlTemplate pour le contrôle Button.
Quand créer un ControlTemplate
Les contrôles ont de nombreuses propriétés, telles que Background, Foreground et FontFamily. Ces propriétés contrôlent différents aspects de l’apparence du contrôle, mais les modifications que vous pouvez apporter en définissant ces propriétés sont limitées. Par exemple, vous pouvez définir la propriété Foreground sur bleu et FontStyle sur italique sur un CheckBox. Quand vous souhaitez personnaliser l’apparence du contrôle au-delà de ce qui est défini par les autres propriétés du contrôle, vous créez un ControlTemplate.
Dans la plupart des interfaces utilisateur, un bouton a la même apparence générale : un rectangle avec du texte. Si vous souhaitez créer un bouton arrondi, vous pouvez créer un contrôle qui hérite du bouton ou recréer la fonctionnalité du bouton. En outre, le nouveau contrôle utilisateur fournirait le visuel circulaire.
Vous pouvez éviter de créer de nouveaux contrôles en personnalisant la disposition visuelle d’un contrôle existant. Avec un bouton arrondi, vous créez un ControlTemplate avec la disposition visuelle souhaitée.
En revanche, si vous avez besoin d’un contrôle avec de nouvelles fonctionnalités, différentes propriétés et de nouveaux paramètres, vous créez une nouvelle UserControl.
Conditions préalables
Créez une application WPF et, dans MainWindow.xaml (ou une autre fenêtre de votre choix), définissez les propriétés suivantes sur l’élément <Window> :
| Propriété | Valeur |
|---|---|
| Title | Template Intro Sample |
| SizeToContent | WidthAndHeight |
| MinWidth | 250 |
Définissez le contenu de l’élément <de la fenêtre> au code XAML suivant :
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
À la fin, le fichier MainWindow.xaml doit ressembler à ce qui suit :
<Window x:Class="IntroToStylingAndTemplating.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Si vous exécutez l’application, il se présente comme suit :
Créer un ControlTemplate
La façon la plus courante de déclarer une ControlTemplate est une ressource dans la section Resources dans un fichier XAML. Étant donné que les modèles sont des ressources, ils obéissent aux mêmes règles d’étendue que celles qui s’appliquent à toutes les ressources. En d’autres termes, lorsque vous déclarez un modèle affecte l’endroit où le modèle peut être appliqué. Par exemple, si vous déclarez le modèle dans l’élément racine de votre fichier XAML de définition d’application, le modèle peut être utilisé n’importe où dans votre application. Si vous définissez le modèle dans une fenêtre, seuls les contrôles de cette fenêtre peuvent utiliser le modèle.
Pour commencer, ajoutez un élément Window.Resources à votre fichier MainWindow.xaml :
<Window x:Class="IntroToStylingAndTemplating.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<Window.Resources>
</Window.Resources>
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Créez un nouveau ControlTemplate <> avec les propriétés suivantes définies :
| Propriété | Valeur |
|---|---|
| x :Key | roundbutton |
| TargetType | Button |
Ce modèle de contrôle est simple :
- un élément racine pour le contrôle, un Grid
- un Ellipse pour dessiner l’apparence arrondie du bouton
- un ContentPresenter pour afficher le contenu du bouton spécifié par l’utilisateur
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
TemplateBinding
Lorsque vous créez une nouvelle ControlTemplate, vous pouvez toujours utiliser les propriétés publiques pour modifier l’apparence du contrôle. Le TemplateBinding extension de balisage lie une propriété d’un élément qui se trouve dans l'ControlTemplate à une propriété publique définie par le contrôle. Lorsque vous utilisez un TemplateBinding, vous activez les propriétés sur le contrôle pour agir en tant que paramètres pour le modèle. Autrement dit, lorsqu’une propriété d’un contrôle est définie, cette valeur est transmise à l’élément qui a le TemplateBinding dessus.
Ellipse
Notez que les propriétés Fill et Stroke de l’élément Ellipse <> sont liées aux propriétés Foreground et Background du contrôle.
Présentateur de Contenu
Un élément <ContentPresenter> est également ajouté au modèle. Étant donné que ce modèle est conçu pour un bouton, prenez en compte que le bouton hérite de ContentControl. Le bouton présente le contenu de l’élément. Vous pouvez définir n’importe quoi à l’intérieur du bouton, tel que du texte brut ou même un autre contrôle. Les deux boutons suivants sont valides :
<Button>My Text</Button>
<!-- and -->
<Button>
<CheckBox>Checkbox in a button</CheckBox>
</Button>
Dans les deux exemples précédents, le texte et la case à cocher sont définis en tant que propriété Button.Content. Tout ce qui est défini comme contenu peut être présenté par le biais d’un <ContentPresenter>, c’est-à-dire ce que fait le modèle.
Si le ControlTemplate est appliqué à un type ContentControl, tel qu’un Button, un ContentPresenter est recherché dans l’arborescence d’éléments. Si la ContentPresenter est trouvée, le modèle lie automatiquement la propriété Content du contrôle au ContentPresenter.
Utiliser le modèle
Recherchez les boutons déclarés au début de cet article.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
Définissez la propriété Template du deuxième bouton sur la ressource roundbutton :
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>
Si vous exécutez le projet et examinez le résultat, vous verrez que le bouton a un arrière-plan arrondi.
Vous avez peut-être remarqué que le bouton n’est pas un cercle, mais qu’il est asymétrique. En raison du fonctionnement de l’élément <Ellipse>, il s’étend toujours pour remplir l’espace disponible. Uniformisez le cercle en modifiant les propriétés width et height du bouton à la même valeur :
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>
Ajouter un déclencheur
Même si un bouton avec un modèle appliqué semble différent, il se comporte comme n’importe quel autre bouton. Si vous appuyez sur le bouton, l’événement Click se déclenche. Toutefois, vous avez peut-être remarqué que lorsque vous déplacez votre souris sur le bouton, les visuels du bouton ne changent pas. Ces interactions visuelles sont toutes définies par le modèle.
Avec les systèmes dynamiques d’événements et de propriétés que WPF fournit, vous pouvez regarder une propriété spécifique pour une valeur, puis restyle le modèle le cas échéant. Dans cet exemple, vous allez regarder la propriété IsMouseOver du bouton. Lorsque la souris est sur le contrôle, stylez la <Ellipse> avec une nouvelle couleur. Ce type de déclencheur est appelé PropertyTrigger.
Pour que cela fonctionne, vous devez ajouter un nom à l'<Ellipse> à laquelle vous pouvez vous référer. Donnez-lui le nom de backgroundElement.
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
Ensuite, ajoutez une nouvelle Trigger à la collection ControlTemplate.Triggers. Le déclencheur surveille l’événement IsMouseOver pour la valeur true.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Ensuite, ajoutez un <Setter> au <Trigger> qui change la propriété Fill de l'<Ellipse> en une nouvelle couleur.
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
Exécutez le projet. Notez que lorsque vous déplacez la souris sur le bouton, la couleur du <Ellipse> change.
Utiliser un VisualState
Les états visuels sont définis et déclenchés par un contrôle. Par exemple, lorsque la souris est déplacée sur le contrôle, l’état CommonStates.MouseOver est déclenché. Vous pouvez animer les modifications de propriété en fonction de l’état actuel du contrôle. Dans la section précédente, un <PropertyTrigger> a été utilisé pour changer l’arrière-plan du bouton en AliceBlue, lorsque la propriété IsMouseOver était true. Au lieu de cela, créez un état visuel qui anime la modification de cette couleur, ce qui offre une transition fluide. Pour plus d’informations sur VisualStates, consultez Styles et modèles dans WPF.
Pour convertir le <PropertyTrigger> en un état visuel animé, d'abord, supprimez l'élément <ControlTemplate.Triggers> de votre modèle.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Ensuite, dans la racine <Grid> du modèle de contrôle, ajoutez l’élément <VisualStateManager.VisualStateGroups> avec un <VisualStateGroup> pour CommonStates. Définissez deux états, Normal et MouseOver.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
</VisualState>
<VisualState Name="MouseOver">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Toutes les animations définies dans un <VisualState> sont appliquées lorsque cet état est déclenché. Créez des animations pour chaque état. Les animations sont placées à l’intérieur d’un élément Storyboard <>. Pour plus d’informations sur les storyboards, consultez Vue d’ensemble des storyboards.
Normale
Cet état anime le remplissage de l'ellipse, en le rétablissant à la couleur
Backgrounddu contrôle.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>MouseOver
Cet état change la couleur de l’ellipse
Backgroundà une nouvelle couleur :Yellow.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
Le <ControlTemplate> doit maintenant ressembler à ce qui suit.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{TemplateBinding Background}"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
<VisualState Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Yellow"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Exécutez le projet. Notez que lorsque vous déplacez la souris sur le bouton, la couleur du <Ellipse> s’anime.
Étapes suivantes
- Créer un style pour un contrôle
- styles et modèles
- Vue d’ensemble des ressources XAML
.NET Desktop feedback