Un ControlTemplate spécifie la structure visuelle et le comportement visuel d'un contrôle. Vous pouvez personnaliser l'apparence d'un contrôle en lui donnant un nouveau ControlTemplate. Lorsque vous créez un ControlTemplate, vous remplacez l'apparence d'un contrôle existant sans modifier sa fonctionnalité. Par exemple, vous pouvez donner aux boutons de votre application une forme arrondie à la place de la forme carrée par défaut, mais le bouton déclenchera toujours l'événement Click.
Cette rubrique décrit les différents composants d'un ControlTemplate, présente la création d'un ControlTemplate simple pour un Button et explique comment interpréter le contrat de contrôle d'un contrôle de sorte que vous puissiez personnaliser son apparence. Étant donné que vous créez un ControlTemplate en XAML, vous pouvez modifier l'apparence d'un contrôle sans écrire de code. Les exemples de cette rubrique présentent le code XAML utilisé pour personnaliser l'apparence d'un Button. Pour obtenir l'exemple complet présenté dans cette rubrique, consultez Procédure pas à pas : personnalisation de l'apparence d'un bouton à l'aide d'un ControlTemplate. Vous pouvez également utiliser un concepteur tel que Microsoft Expression Blend 2 Service Pack 1 pour parvenir au même résultat. Pour plus d'informations sur l'utilisation d'Expression Blend 2 SP1, consultez Create a Reusable Template for a System Control.
Cliquez sur le lien suivant pour afficher l'exemple de ControlTemplate qui est utilisé dans cette rubrique.
Exécuter cet exemple
Cette rubrique comprend les sections suivantes.
Cette rubrique part du principe que comprenez la création et l'utilisation des contrôles et des styles (Mise en route avec les contrôles), ainsi que les concepts de base de la personnalisation des contrôles (Personnalisation des contrôles).
Quand créer un ControlTemplate
Les contrôles ont de nombreuses propriétés, telles que Background, Foreground et FontFamily, que vous pouvez définir pour spécifier différents aspects de l'apparence du contrôle ; cependant, les modifications que vous pouvez apporter en définissant ces propriétés sont limitées. Par exemple, vous pouvez affecter la valeur blue à la propriété Foreground et la valeur italic à la propriété FontStyle d'un CheckBox.
S'il n'était pas possible de créer un ControlTemplate pour les contrôles, tous les contrôles de toutes les applications Silverlight auraient la même apparence générale, ce qui limiterait les possibilités de créer une application avec une apparence personnalisée. Par défaut, chaque CheckBox présente des caractéristiques similaires. Par exemple, le contenu du CheckBox se situe toujours à droite de l'indicateur de sélection et la coche est toujours utilisée pour indiquer que le CheckBox est activé.
Vous créez un ControlTemplate lorsque 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. Dans l'exemple du CheckBox, supposons que vous souhaitiez que le contenu de la case à cocher apparaisse au-dessus de l'indicateur de sélection et qu'un X indique que le CheckBox est activé. Vous spécifiez qu'il s'agit du ControlTemplate du CheckBox.
Cliquez sur le lien suivant pour afficher un CheckBox qui utilise un ControlTemplate par défaut et un CheckBox qui utilise un ControlTemplate personnalisé pour placer le contenu du CheckBox au-dessus de l'indicateur de sélection et afficher un X lorsque le CheckBox est activé.
Exécuter cet exemple
Le ControlTemplate du CheckBox de cet exemple est relativement complexe ; cette rubrique utilise donc un exemple plus simple pour la création d'un ControlTemplate d'un Button.
Comment définir le ControlTemplate en XAML
La propriété Template spécifie le ControlTemplate d'un contrôle. Comme de nombreuses propriétés, la propriété Template peut être définie de plusieurs manières :
L'exemple suivant présente la définition de la propriété Template en local et la définition du ControlTemplate inline.
<Button Content="Button1">
<Button.Template>
<ControlTemplate TargetType="Button">
<!--Define the ControlTemplate here.-->
</ControlTemplate>
</Button.Template>
</Button>
L'exemple suivant présente la définition du ControlTemplate en tant que ressource et la définition du Template sur une référence à la ressource.
<StackPanel>
<StackPanel.Resources>
<ControlTemplate TargetType="Button" x:Key="newTemplate">
<!--Define the ControlTemplate here.-->
</ControlTemplate>
</StackPanel.Resources>
<Button Template="{StaticResource newTemplate}" Content="Button1"/>
</StackPanel>
L'exemple suivant présente la définition de la propriété Template et la définition du ControlTemplate dans un Style.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="Button" x:Key="newTemplate">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<!--Define the ControlTemplate here.-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<Button Style="{StaticResource newTemplate}" Content="Button1"/>
</StackPanel>
Même si ces trois méthodes sont valides pour définir un ControlTemplate, il est probablement plus courant de voir la propriété Template définie dans un Style. Lorsque vous voyez qu'un ControlTemplate est défini dans un Style, sachez que le style définit seulement la propriété Template, exactement comme pour toute autre propriété.
Modification de la structure visuelle d'un contrôle
Dans Silverlight, un contrôle est souvent un composite d'objets FrameworkElement. Lorsque vous créez un ControlTemplate, vous combinez des objets FrameworkElement pour générer un seul contrôle. Un ControlTemplate doit avoir un seul FrameworkElement en tant qu'élément racine. Ce dernier contient généralement d'autres objets FrameworkElement. Cette combinaison d'objets constitue la structure visuelle du contrôle.
L'exemple suivant crée un ControlTemplate personnalisé pour le Button. Le ControlTemplate crée la structure visuelle du Button. Cet exemple ne modifie pas l'apparence du bouton lorsque vous pointez sur lui ou cliquez dessus. La modification de l'apparence du bouton lorsque celui-ci est dans un autre état est décrite plus loin dans cette rubrique.
Dans cet exemple, la structure visuelle se compose des parties suivantes :
<ControlTemplate TargetType="Button">
<Border x:Name="RootElement">
<!--Create the SolidColorBrush for the Background
as an object elemment and give it a name so
it can be referred to elsewhere in the control template.-->
<Border.Background>
<SolidColorBrush x:Name="BorderBrush" Color="Black"/>
</Border.Background>
<!--Create a border that has a different color by adding smaller grid.
The background of this grid is specificied by the button's Background
property.-->
<Grid Margin="4" Background="{TemplateBinding Background}">
<!--Use a ContentPresenter to display the Content of
the Button.-->
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,5,4,4" />
</Grid>
</Border>
</ControlTemplate>
Conservation de la fonctionnalité des propriétés d'un contrôle en utilisant TemplateBinding
Lorsque vous créez un ControlTemplate, vous trouverez peut-être toujours pratique d'utiliser les propriétés publiques pour modifier l'apparence du contrôle. L'extension de balisage TemplateBinding lie une propriété d'un élément figurant dans le ControlTemplate à une propriété publique définie par le contrôle. L'exemple précédent utilise l'extension de balisage TemplateBinding pour lier les propriétés des éléments du ControlTemplate aux propriétés publiques définies par le bouton. Par exemple, la propriété Background du Border a la valeur {TemplateBinding Background}. Étant donné que la propriété Background est liée par modèle, vous pouvez créer plusieurs boutons qui utilisent le même ControlTemplate et affecter des valeurs différentes à Background pour chaque bouton. Si la propriété Background n'était pas liée par modèle dans le ControlTemplate, la définition de la propriété Background d'un bouton n'aurait aucune incidence sur l'apparence du bouton.
La classe Control définit plusieurs propriétés qui peuvent être utilisées par le modèle de contrôle pour avoir un effet sur le contrôle lorsqu'elles sont définies. La façon dont ControlTemplate utilise la propriété dépend de la propriété. ControlTemplate doit utiliser la propriété de l'une des façons suivantes :
Le tableau suivant répertorie les propriétés visuelles héritées par un contrôle de la classe Control. Il indique également si le modèle de contrôle par défaut d'un contrôle utilise la valeur de propriété héritée ou s'il est lié par modèle.
Propriété | Méthode d'utilisation |
|---|
Background | Liaison de modèle |
BorderThickness | Liaison de modèle |
BorderBrush | Liaison de modèle |
FontFamily | Héritage de propriété ou liaison de modèle |
FontSize | Héritage de propriété ou liaison de modèle |
FontStretch | Héritage de propriété ou liaison de modèle |
FontWeight | Héritage de propriété ou liaison de modèle |
Foreground | Héritage de propriété ou liaison de modèle |
HorizontalContentAlignment | Liaison de modèle |
Padding | Liaison de modèle |
VerticalContentAlignment | Liaison de modèle |
Le tableau ci-dessus ne répertorie que les propriétés visuelles héritées de la classe Control. En dehors des propriétés répertoriées ci-dessus, un contrôle peut également hériter des propriétés DataContext, Language et TextDecorations de l'élément d'infrastructure parent.
En outre, si le ContentPresenter est dans le ControlTemplate d'un ContentControl, le ContentPresenter se liera automatiquement aux propriétés ContentTemplate et Content. De même, un ItemsPresenter qui est dans le ControlTemplate d'un ItemsControl se liera automatiquement aux propriétés Items et ItemsPresenter.
L'exemple suivant crée deux boutons qui utilisent le ControlTemplate défini dans l'exemple précédent. Cet exemple définit les propriétés Background, Foreground et FontSize de chaque bouton. La définition de la propriété Background a une incidence, car elle est liée par modèle dans le ControlTemplate. Même si les propriétés Foreground et FontSize ne sont pas liées par modèle, leur définition a une incidence, car leurs valeurs sont héritées.
Exécuter cet exemple
<StackPanel>
<Button Style="{StaticResource newTemplate}"
Background="Navy" Foreground="White" FontSize="14"
Content="Button1"/>
<Button Style="{StaticResource newTemplate}"
Background="Purple" Foreground="White" FontSize="14"
Content="Button2" Click="Button_Click"/>
</StackPanel>
Modification de l'apparence d'un contrôle en fonction de son état
La différence entre un bouton avec son apparence par défaut et le bouton de l'exemple précédent est que le bouton par défaut change légèrement selon son état. Par exemple, l'apparence du bouton par défaut change lorsque l'utilisateur clique dessus ou pointe sur lui. Bien que le ControlTemplate ne modifie pas la fonctionnalité d'un contrôle, il en modifie le comportement visuel. Un comportement visuel décrit l'apparence du contrôle lorsque ce dernier est dans état particulier. Pour comprendre la différence entre la fonctionnalité et le comportement visuel d'un contrôle, considérez l'exemple du bouton. La fonctionnalité du bouton consiste à déclencher l'événement Click lorsque l'utilisateur clique dessus, alors que son comportement visuel consiste à changer d'apparence lorsque l'utilisateur pointe sur lui ou clique dessus.
Vous utilisez des objets VisualState pour spécifier l'apparence d'un contrôle lorsque ce dernier est dans un état particulier. Un objet VisualState contient un Storyboard qui modifie l'apparence des éléments qui sont dans le ControlTemplate. Vous n'avez aucun code à écrire pour cela, car la logique du contrôle modifie l'état à l'aide du VisualStateManager. Lorsque le contrôle passe à l'état qui est spécifié par la propriété VisualState..::.Name, le storyboard commence. Lorsque le contrôle sort de cet état, le Storyboard cesse.
L'exemple suivant présente le VisualState qui modifie l'apparence d'un Button lorsque l'utilisateur pointe sur lui. Le Name du VisualState correspond au nom spécifié par le TemplateVisualStateAttribute dans la classe Button. Le Storyboard modifie la couleur de la bordure du bouton en modifiant la couleur du BorderBrush. Si vous vous reportez à l'exemple ControlTemplate du début de cette rubrique, vous vous souviendrez que BorderBrush est le nom du SolidColorBrush affecté au Background du Border.
<!--Change the border of the button to red when the
mouse is over the button.-->
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</vsm:VisualState>
Le contrôle est chargé de définir les états dans le cadre de son contrat de contrôle, lequel est décrit en détail dans Personnalisation des autres contrôles grâce à une bonne compréhension du contrat de contrôle, plus loin dans cette rubrique. Les états d'un contrôle sont spécifiés par le TemplateVisualStateAttribute, lequel est placé sur la définition de classe du contrôle. Un TemplateVisualStateAttribute spécifie le nom de l'état et le nom du groupe d'états auquel cet état appartient. L'exemple suivant présente les états qui sont spécifiés pour le Button.
<TemplateVisualStateAttribute(Name:="Pressed", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Focused", GroupName:="FocusStates")> _
<TemplateVisualStateAttribute(Name:="Normal", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="MouseOver", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Disabled", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Unfocused", GroupName:="FocusStates")> _
Public Class Button
Inherits ButtonBase
End Class
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
public class Button : ButtonBase
{
}
La propriété TemplateVisualStateAttribute..::.GroupName spécifie le groupe auquel appartient un état. Dans l'exemple précédent, le Button définit deux groupes d'états : le groupe CommonStates contient les états Normal, MouseOver, Pressed et Disabled Le groupe FocusStates contient les états Focused et Unfocused. Les états d'un même groupe d'état s'excluent mutuellement. Le contrôle est toujours exactement dans un état par groupe. Par exemple, un Button peut avoir le focus même lorsque le pointeur de la souris n'est pas placé dessus, de sorte qu'un Button à l'état Focused peut être à l'état MouseOver, Pressed ou Normal.
Vous ajoutez des objets VisualState à des objets VisualStateGroup. Vous ajoutez des objets VisualStateGroup à la propriété jointe VisualStateManager.VisualStateGroups, que vous définissez sur le FrameworkElement racine du ControlTemplate. L'exemple suivant définit les objets VisualState pour les états Normal, MouseOver et Pressed, lesquels figurent tous dans le groupe CommonStates. L'état Disabled et les états du groupe FocusStates sont omis pour que l'exemple reste concis, mais ils figurent dans l'exemple complet fourni dans Procédure pas à pas : personnalisation de l'apparence d'un bouton à l'aide d'un ControlTemplate.
Exécuter cet exemple
<ControlTemplate TargetType="Button"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
<Border x:Name="RootElement">
<vsm:VisualStateManager.VisualStateGroups>
<!--Define the states for the common states.
The states in the VisualStateGroup are mutually exclusive to
each other.-->
<vsm:VisualStateGroup x:Name="CommonStates">
<!--The Normal state is the state the button is in
when it is not in another state from this VisualStateGroup.-->
<vsm:VisualState x:Name="Normal" />
<!--Change the SolidColorBrush, BorderBrush, to red when the
mouse is over the button.-->
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</vsm:VisualState>
<!--Change the SolidColorBrush, BorderBrush, to Transparent when the
button is pressed.-->
<vsm:VisualState x:Name="Pressed">
<Storyboard >
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Transparent"/>
</Storyboard>
</vsm:VisualState>
<!--The Disabled state is omitted for brevity.-->
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Border.Background>
<SolidColorBrush x:Name="BorderBrush" Color="Black"/>
</Border.Background>
<Grid Background="{TemplateBinding Background}" Margin="4">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,5,4,4" />
</Grid>
</Border>
</ControlTemplate>
Spécification du comportement d'un contrôle lors des transitions entre états
Si vous exécutez l'exemple précédent, vous remarquerez que l'apparence d'un bouton change lorsque vous pointez sur lui. L'apparence du bouton change également lorsque vous cliquez dessus, mais vous n'en verrez l'effet que si vous maintenez le bouton de la souris enfoncé pendant une seconde complète. Par défaut, une seconde est nécessaire au déclenchement d'une animation. Comme les utilisateurs mettent généralement moins de temps pour appuyer sur un bouton et le relâcher, la rétroaction visuelle ne sera pas efficace si vous laissez le ControlTemplate dans son état par défaut.
Vous pouvez spécifier la durée nécessaire à une animation pour effectuer une transition douce entre les états d'un contrôle en ajoutant des objets VisualTransition au ControlTemplate. Lorsque vous créez un VisualTransition, vous spécifiez un ou plusieurs des éléments suivants :
Temps nécessaire à une transition entre des états.
Modifications supplémentaires dans l'apparence du contrôle qui ont lieu lors de la transition.
États auxquels le VisualTransition est appliqué.
Spécification de la durée d'une transition
Vous pouvez spécifier la durée d'une transition en définissant la propriété GeneratedDuration. L'exemple précédent possède un VisualState qui spécifie que la bordure du bouton devient transparente lorsque l'utilisateur appuie sur le bouton, mais l'animation met trop de temps pour se déclencher lorsque l'utilisateur appuie sur le bouton et le relâche immédiatement. Vous pouvez utiliser un VisualTransition pour spécifier la durée nécessaire au contrôle pour que son état passe à Pressed. L'exemple suivant spécifie que le contrôle nécessite un centième de seconde pour passer à l'état Pressed.
<!--Take one hundredth of a second to transition to the
Pressed state.-->
<vsm:VisualTransition To="Pressed"
GeneratedDuration="0:0:0.01" />
Spécification de modifications de l'apparence du contrôle pendant une transition
Le VisualTransition contient un Storyboard qui commence lorsque le contrôle effectue des transitions entre états. Par exemple, vous pouvez spécifier qu'une animation particulière a lieu lorsque le contrôle effectue des transitions de l'état MouseOver vers l'état Normal. L'exemple suivant crée un VisualTransition qui spécifie que lorsque l'utilisateur éloigne le pointeur de la souris du bouton, la bordure de ce dernier passe du bleu au jaune et enfin au noir en 1,5 secondes.
<!--Take one and a half seconds to transition from the
MouseOver state to the Normal state.
Have the SolidColorBrush, BorderBrush, fade to blue,
then to yellow, and then to black in that time.-->
<vsm:VisualTransition From="MouseOver" To="Normal"
GeneratedDuration="0:0:1.5">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Color"
Storyboard.TargetName="BorderBrush"
FillBehavior="HoldEnd" >
<ColorAnimationUsingKeyFrames.KeyFrames>
<LinearColorKeyFrame Value="Blue"
KeyTime="0:0:0.5" />
<LinearColorKeyFrame Value="Yellow"
KeyTime="0:0:1" />
<LinearColorKeyFrame Value="Black"
KeyTime="0:0:1.5" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualTransition>
Spécification du moment où un VisualTransition est appliqué
Dans l'exemple précédent, le VisualTransition est appliqué lorsque le contrôle passe de l'état MouseOver à l'état Normal ; dans l'exemple antérieur, le VisualTransition est appliqué lorsque le contrôle passe à l'état Pressed. Un VisualTransition peut être restreint de manière à ne s'appliquer qu'à certains états, ou il peut être appliqué chaque fois que le contrôle effectue des transitions entre états. Pour restreindre le moment où un VisualTransition est appliqué, il convient de définir les propriétés To et From. Le tableau suivant décrit les niveaux de restriction, du plus restrictif au moins restrictif.
Type de restriction | Valeur de From | Valeur de To |
|---|
D'un état spécifié vers un autre état spécifié | Nom d'un VisualState | Nom d'un VisualState |
De n'importe quel état vers un état spécifié | Non définie | Nom d'un VisualState |
D'un état spécifié vers n'importe quel état | Nom d'un VisualState | Non définie |
De n'importe quel état vers tout autre état | Non définie | Non définie |
Vous pouvez avoir plusieurs objets VisualTransition dans un VisualStateGroup qui font référence au même état, mais ces objets seront utilisés dans l'ordre spécifié dans le tableau ci-dessus. L'exemple suivant contient deux objets VisualTransition. Lorsque contrôle effectue une transition de l'état Pressed vers l'état MouseOver, c'est le VisualTransition dans lequel les propriétés From et To sont définies qui est utilisé. Lorsque le contrôle effectue une transition d'un état différent de Pressed vers l'état MouseOver, c'est l'autre état qui est utilisé.
<!--Take one half second to trasition to the MouseOver state.-->
<vsm:VisualTransition To="MouseOver"
GeneratedDuration="0:0:0.5" />
<!--Take one hundredth of a second to transition from the
Pressed state to the MouseOver state.-->
<vsm:VisualTransition From="Pressed" To="MouseOver"
GeneratedDuration="0:0:0.01" />
Le VisualStateGroup comporte une propriété Transitions qui contient les objets VisualTransition qui s'appliquent aux objets VisualState du VisualStateGroup. En tant qu'auteur du ControlTemplate, vous êtes libre d'inclure tout VisualTransition de votre choix. Toutefois, si les propriétés To et From sont définies par des noms d'états qui ne figurent pas dans le VisualStateGroup, le VisualTransition est ignoré.
L'exemple suivant présente le VisualStateGroup de CommonStates. Cet exemple définit un VisualTransition pour chacune des transitions suivantes du bouton.
Exécuter cet exemple
<vsm:VisualStateGroup x:Name="CommonStates">
<!--Define the VisualTransitions that can be used when the control
transitions between VisualStates that are defined in the
VisualStatGroup.-->
<vsm:VisualStateGroup.Transitions>
<!--Take one hundredth of a second to transition to the
Pressed state.-->
<vsm:VisualTransition To="Pressed"
GeneratedDuration="0:0:0.01" />
<!--Take one half second to trasition to the MouseOver state.-->
<vsm:VisualTransition To="MouseOver"
GeneratedDuration="0:0:0.5" />
<!--Take one hundredth of a second to transition from the
Pressed state to the MouseOver state.-->
<vsm:VisualTransition From="Pressed" To="MouseOver"
GeneratedDuration="0:0:0.01" />
<!--Take one and a half seconds to transition from the
MouseOver state to the Normal state.
Have the SolidColorBrush, BorderBrush, fade to blue,
then to yellow, and then to black in that time.-->
<vsm:VisualTransition From="MouseOver" To="Normal"
GeneratedDuration="0:0:1.5">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Color"
Storyboard.TargetName="BorderBrush"
FillBehavior="HoldEnd" >
<ColorAnimationUsingKeyFrames.KeyFrames>
<LinearColorKeyFrame Value="Blue"
KeyTime="0:0:0.5" />
<LinearColorKeyFrame Value="Yellow"
KeyTime="0:0:1" />
<LinearColorKeyFrame Value="Black"
KeyTime="0:0:1.5" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualTransition>
</vsm:VisualStateGroup.Transitions>
<!--The remainder of the VisualStateGroup is the
same as the previous example.-->
<vsm:VisualState x:Name="Normal" />
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Pressed">
<Storyboard >
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Transparent"/>
</Storyboard>
</vsm:VisualState>
<!--The Disabled state is omitted for brevity.-->
</vsm:VisualStateGroup>
Personnalisation des autres contrôles grâce à une bonne compréhension du contrat de contrôle
Un contrôle qui utilise un ControlTemplate pour spécifier sa structure visuelle (en utilisant des objets FrameworkElement) et son comportement visuel (en utilisant des objets VisualState) utilise le modèle de contrôle des composants. Nombre de contrôles fournis avec Silverlight et de contrôles tiers utilisent ce modèle. Les composants que doit connaître l'auteur d'un ControlTemplate sont communiquées via le contrat de contrôle. Lorsque vous connaissez les composants d'un contrat de contrôle, vous pouvez personnaliser l'apparence de tout contrôle qui utilise le modèle de contrôle des composants.
Un contrat de contrôle comporte trois éléments :
Les éléments visuels utilisés par la logique du contrôle.
Les états du contrôle et le groupe auquel appartient chaque état.
Les propriétés publiques qui affectent visuellement le contrôle.
Éléments visuels du contrat de contrôle
La logique d'un contrôle interagit parfois avec un FrameworkElement qui se trouve dans le ControlTemplate. Par exemple, le contrôle peut gérer un événement de l'un de ses éléments. Lorsqu'un contrôle s'attend à trouver un FrameworkElement particulier dans le ControlTemplate, il doit communiquer cette information à l'auteur du ControlTemplate. Le contrôle utilise le TemplatePartAttribute pour communiquer le type d'élément attendu et le nom que doit porter cet élément. Le Button n'a pas de composants FrameworkElement dans son contrat de contrôle, à la différence d'autres contrôles tels que ComboBox.
L'exemple suivant présente les objets TemplatePartAttribute qui sont spécifiés dans la classe ComboBox. La logique de ComboBox s'attend à trouver un Popup nommé Popup et un ContentPresenter nommé ContentPresenter dans son ControlTemplate.
<TemplatePartAttribute(Name:="ContentPresenter", Type:=GetType(ContentPresenter))> _
<TemplatePartAttribute(Name:="Popup", Type:=GetType(Popup))> _
Public Class ComboBox
Inherits ItemsControl
End Class
[TemplatePartAttribute(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
[TemplatePartAttribute(Name = "Popup", Type = typeof(Popup))]
public class ComboBox : ItemsControl
{
}
L'exemple suivant présente un ControlTemplate simplifié pour le ComboBox qui inclut les éléments qui sont spécifiés par les objets TemplatePartAttribute dans la classe ComboBox.
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="ContentPresenterBorder">
<Grid>
<ToggleButton x:Name="DropDownToggle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="-1" HorizontalContentAlignment="Right">
<Path x:Name="BtnArrow" Height="4" Width="8"
Stretch="Uniform" Margin="0,0,6,0" Fill="Black"
Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2">
<TextBlock Text=" " />
</ContentPresenter>
</Grid>
</Border>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder"
HorizontalAlignment="Stretch" Height="Auto"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black" Background="White" CornerRadius="3">
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
États du contrat de contrôle
Propriétés du contrat de contrôle
Les propriétés publiques qui affectent visuellement le contrôle sont également incluses dans le contrat de contrôle. Vous pouvez définir ces propriétés pour modifier l'apparence du contrôle sans créer de nouveau ControlTemplate. Vous pouvez également utiliser l'extension de balisage TemplateBinding pour lier les propriétés d'éléments qui figurent dans le ControlTemplate à des propriétés publiques définies par le Button.
Pour les contrôles fournis avec Silverlight 3, vous pouvez connaître l'élément visuel et les états inclus dans le contrat d'un contrôle en consultant la rubrique de référence relative au contrôle en question. Par exemple, la section de syntaxe de la référence relative à la classe ComboBox présente le TemplatePartAttribute et le TemplateVisualStateAttribute spécifiés par le ComboBox. Bien que votre application doive s'exécuter sans lever d'exception si vous n'incluez pas un FrameworkElement ou un VisualState attendu, le contrôle peut ne pas se comporter comme prévu. Toute propriété publique qui affecte visuellement le contrôle fait également partie du contrat de contrôle.
L'exemple suivant résume le contrat de contrôle du bouton.
<TemplateVisualState(Name:="Normal", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="MouseOver", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Pressed", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Disabled", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Unfocused", GroupName:="FocusStates")> _
<TemplateVisualState(Name:="Focused", GroupName:="FocusStates")> _
Public Class Button
Inherits ButtonBase
Public Shared ReadOnly BackgroundProperty As DependencyProperty
Public Shared ReadOnly BorderBrushProperty As DependencyProperty
Public Shared ReadOnly BorderThicknessProperty As DependencyProperty
Public Shared ReadOnly ContentProperty As DependencyProperty
Public Shared ReadOnly ContentTemplateProperty As DependencyProperty
Public Shared ReadOnly FontFamilyProperty As DependencyProperty
Public Shared ReadOnly FontSizeProperty As DependencyProperty
Public Shared ReadOnly FontStretchProperty As DependencyProperty
Public Shared ReadOnly FontStyleProperty As DependencyProperty
Public Shared ReadOnly FontWeightProperty As DependencyProperty
Public Shared ReadOnly ForegroundProperty As DependencyProperty
Public Shared ReadOnly HorizontalContentAlignmentProperty As DependencyProperty
Public Shared ReadOnly PaddingProperty As DependencyProperty
Public Shared ReadOnly TextAlignmentProperty As DependencyProperty
Public Shared ReadOnly TextDecorationsProperty As DependencyProperty
Public Shared ReadOnly TextWrappingProperty As DependencyProperty
Public Shared ReadOnly VerticalContentAlignmentProperty As DependencyProperty
Public Background As Brush
Public BorderBrush As Brush
Public BorderThickness As Thickness
Public Content As Object
Public ContentTemplate As DataTemplate
Public FontFamily As FontFamily
Public FontSize As Double
Public FontStretch As FontStretch
Public FontStyle As FontStyle
Public FontWeight As FontWeight
Public Foreground As Brush
Public HorizontalContentAlignment As HorizontalAlignment
Public Padding As Thickness
Public TextAlignment As TextAlignment
Public TextDecorations As TextDecorationCollection
Public TextWrapping As TextWrapping
Public VerticalContentAlignment As VerticalAlignment
End Class
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
public class Button : ButtonBase
{
public static readonly DependencyProperty BackgroundProperty;
public static readonly DependencyProperty BorderBrushProperty;
public static readonly DependencyProperty BorderThicknessProperty;
public static readonly DependencyProperty ContentProperty;
public static readonly DependencyProperty ContentTemplateProperty;
public static readonly DependencyProperty FontFamilyProperty;
public static readonly DependencyProperty FontSizeProperty;
public static readonly DependencyProperty FontStretchProperty;
public static readonly DependencyProperty FontStyleProperty;
public static readonly DependencyProperty FontWeightProperty;
public static readonly DependencyProperty ForegroundProperty;
public static readonly DependencyProperty HorizontalContentAlignmentProperty;
public static readonly DependencyProperty PaddingProperty;
public static readonly DependencyProperty TextAlignmentProperty;
public static readonly DependencyProperty TextDecorationsProperty;
public static readonly DependencyProperty TextWrappingProperty;
public static readonly DependencyProperty VerticalContentAlignmentProperty;
public Brush Background { get; set; }
public Brush BorderBrush { get; set; }
public Thickness BorderThickness { get; set; }
public object Content { get; set; }
public DataTemplate ContentTemplate { get; set; }
public FontFamily FontFamily { get; set; }
public double FontSize { get; set; }
public FontStretch FontStretch { get; set; }
public FontStyle FontStyle { get; set; }
public FontWeight FontWeight { get; set; }
public Brush Foreground { get; set; }
public HorizontalAlignment HorizontalContentAlignment { get; set; }
public Thickness Padding { get; set; }
public TextAlignment TextAlignment { get; set; }
public TextDecorationCollection TextDecorations { get; set; }
public TextWrapping TextWrapping { get; set; }
public VerticalAlignment VerticalContentAlignment { get; set; }
}
Lors de la création d'un ControlTemplate, il est souvent plus facile de commencer avec un ControlTemplate existant et de lui apporter des modifications. Vous pouvez effectuer l'une des opérations suivantes pour modifier un ControlTemplate existant :
Pour pouvoir créer un ControlTemplate, vous devez comprendre le fonctionnement du contrat de contrôle. Lorsque vous connaissez les composants d'un contrat de contrôle, vous pouvez créer un ControlTemplate pour les contrôles existants et créer une application présentant une apparence unique.
Autres ressources