Xamarin.Forms modèles de contrôle
Xamarin.Forms Les modèles de contrôle vous permettent de définir la structure visuelle des ContentView
contrôles personnalisés dérivés et ContentPage
des pages dérivées. Les modèles de contrôle séparent l’interface utilisateur d’un contrôle personnalisé ou d’une page, de la logique qui implémente le contrôle ou la page. Du contenu supplémentaire peut également être inséré dans le contrôle personnalisé basé sur un modèle, ou dans la page basée sur un modèle, à un emplacement prédéfini.
Par exemple, vous pouvez créer un modèle de contrôle qui redéfinit l’interface utilisateur fournie par un contrôle personnalisé. Le modèle de contrôle peut ensuite être consommé par l’instance de contrôle personnalisé requise. Vous pouvez également créer un modèle de contrôle qui définit toute interface utilisateur commune qui sera utilisée par plusieurs pages dans une application. Le modèle de contrôle peut ensuite être consommé par plusieurs pages, chacune d’elles affichant toujours son contenu unique.
Créer un ControlTemplate
L’exemple suivant montre le code pour un contrôle personnalisé CardView
:
public class CardView : ContentView
{
public static readonly BindableProperty CardTitleProperty = BindableProperty.Create(nameof(CardTitle), typeof(string), typeof(CardView), string.Empty);
public static readonly BindableProperty CardDescriptionProperty = BindableProperty.Create(nameof(CardDescription), typeof(string), typeof(CardView), string.Empty);
// ...
public string CardTitle
{
get => (string)GetValue(CardTitleProperty);
set => SetValue(CardTitleProperty, value);
}
public string CardDescription
{
get => (string)GetValue(CardDescriptionProperty);
set => SetValue(CardDescriptionProperty, value);
}
// ...
}
La classe CardView
, qui dérive de la classe ContentView
, représente un contrôle personnalisé qui affiche des données dans une disposition de type carte. La classe contient des propriétés, qui sont secondées par des propriétés pouvant être liées, pour les données qu’elle affiche. Toutefois, la classe CardView
ne définit pas d’interface utilisateur. Au lieu de cela, l’interface utilisateur sera définie avec un modèle de contrôle. Pour plus d’informations sur la création ContentView
de contrôles personnalisés dérivés, consultez Xamarin.Forms ContentView.
Un modèle de contrôle est créé avec le type ControlTemplate
. Quand vous créez un ControlTemplate
, vous combinez des objets View
pour générer l’interface utilisateur d’un contrôle personnalisé ou d’une page. Un ControlTemplate
doit avoir une seule View
comme élément racine. Toutefois, l’élément racine contient généralement d’autres objets View
. La combinaison d’objets constitue la structure visuelle du contrôle.
Même si un ControlTemplate
peut être défini inline, l’approche classique consiste à déclarer un ControlTemplate
en tant que ressource dans un dictionnaire de ressources. Les modèles de contrôle étant des ressources, ils obéissent aux mêmes règles de portée que celles qui s’appliquent à toutes les ressources. Par exemple, si vous déclarez un modèle de contrô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 page, seule cette page peut utiliser le modèle de contrôle. Pour plus d’informations sur les ressources, consultez Xamarin.Forms Dictionnaires de ressources.
L’exemple de code XAML suivant montre un ControlTemplate
pour des objets CardView
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
CornerRadius="5"
HasShadow="True"
Padding="8"
HorizontalOptions="Center"
VerticalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Frame IsClippedToBounds="True"
BorderColor="{Binding BorderColor}"
BackgroundColor="{Binding IconBackgroundColor}"
CornerRadius="38"
HeightRequest="60"
WidthRequest="60"
HorizontalOptions="Center"
VerticalOptions="Center">
<Image Source="{Binding IconImageSource}"
Margin="-20"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFill" />
</Frame>
<Label Grid.Column="1"
Text="{Binding CardTitle}"
FontAttributes="Bold"
FontSize="Large"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start" />
<BoxView Grid.Row="1"
Grid.ColumnSpan="2"
BackgroundColor="{Binding BorderColor}"
HeightRequest="2"
HorizontalOptions="Fill" />
<Label Grid.Row="2"
Grid.ColumnSpan="2"
Text="{Binding CardDescription}"
VerticalTextAlignment="Start"
VerticalOptions="Fill"
HorizontalOptions="Fill" />
</Grid>
</Frame>
</ControlTemplate>
</ContentPage.Resources>
...
</ContentPage>
Quand un ControlTemplate
est déclaré en tant que ressource, il doit avoir une clé spécifiée avec l’attribut x:Key
afin de pouvoir être identifié dans le dictionnaire de ressources. Dans cet exemple, l’élément racine du CardViewControlTemplate
est un objet Frame
. L’objet Frame
utilise l’extension de balisage RelativeSource
pour définir comme BindingContext
l’instance de l’objet runtime à laquelle le modèle sera appliqué, connu sous le nom de parent basé sur un modèle. L’objet Frame
utilise une combinaison d’objets Grid
, Frame
, Image
, Label
et BoxView
pour définir la structure visuelle d’un objet CardView
. Les expressions de liaison de ces objets sont résolues par rapport à des propriétés CardView
, en raison de l’héritage du BindingContext
à partir de l’élément Frame
racine. Pour plus d’informations sur l’extension de RelativeSource
balisage, consultez Xamarin.Forms Liaisons relatives.
Consommer un ControlTemplate
Un ControlTemplate
peut être appliqué à un contrôle personnalisé dérivé de ContentView
en affectant comme valeur de sa propriété ControlTemplate
l’objet de modèle de contrôle. De même, un ControlTemplate
peut être appliqué à une page dérivée de ContentPage
en affectant comme valeur de sa propriété ControlTemplate
l’objet de modèle de contrôle. Au moment de l’exécution, quand un ControlTemplate
est appliqué, tous les contrôles définis dans le ControlTemplate
sont ajoutés à l’arborescence d’éléments visuels du contrôle personnalisé basé sur un modèle ou de la page basée sur un modèle.
L’exemple suivant montre l’affectation du CardViewControlTemplate
à la propriété ControlTemplate
de chaque objet CardView
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<StackLayout Margin="30">
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</StackLayout>
</ContentPage>
Dans cet exemple, les contrôles du CardViewControlTemplate
deviennent partie intégrante de l’arborescence d’éléments visuels pour chaque objet CardView
. Étant donné que l’objet Frame
racine pour le modèle de contrôle définit son BindingContext
sur le parent basé sur un modèle, le Frame
et ses enfants résolvent leurs expressions de liaison par rapport aux propriétés de chaque objet CardView
.
Les captures d’écran suivantes montrent le CardViewControlTemplate
appliqué aux trois objets CardView
:
Important
Le moment auquel un ControlTemplate
est appliqué à une instance de contrôle peut être détecté en substituant la méthode OnApplyTemplate
dans le contrôle personnalisé basé sur un modèle ou la page basée sur un modèle. Pour plus d’informations, consultez Obtenir un élément nommé à partir d’un modèle.
Passer des paramètres avec TemplateBinding
L’extension de balisage TemplateBinding
lie une propriété d’un élément qui se trouve dans un ControlTemplate
à une propriété publique définie par la page basée sur un modèle ou le contrôle personnalisé basé sur un modèle. Quand vous utilisez un TemplateBinding
, vous permettez aux propriétés sur le contrôle de faire office de paramètres du modèle. Ainsi, quand une propriété sur un contrôle personnalisé basé sur un modèle ou une page basée sur un modèle est définie, cette valeur est passée à l’élément sur lequel se trouve le TemplateBinding
.
Important
L’expression de balisage TemplateBinding
permet de supprimer la liaison RelativeSource
du modèle de contrôle précédent et remplace les expressions Binding
.
L’extension de balisage TemplateBinding
définit les propriétés suivantes :
Path
, de typestring
, le chemin de la propriété.Mode
, de typeBindingMode
, la direction dans laquelle les modifications se propagent entre la source et la cible.Converter
, de typeIValueConverter
, le convertisseur de valeur de liaison.ConverterParameter
, de typeobject
, le paramètre du convertisseur de valeur de liaison.StringFormat
, de typestring
, le format de chaîne pour la liaison.
ContentProperty
pour l’extension de balisage TemplateBinding
est Path
. Par conséquent, la partie « Path= » de l’extension de balisage peut être omise si le chemin est le premier élément de l’expression TemplateBinding
. Pour plus d’informations sur l’utilisation de ces propriétés dans une expression de liaison, consultez Xamarin.Forms Liaison de données.
Avertissement
L’extension de balisage TemplateBinding
doit être utilisée uniquement dans un ControlTemplate
. Toutefois, si vous tentez d’utiliser une expression TemplateBinding
en dehors d’un ControlTemplate
, une erreur de génération ou une exception est levée.
L’exemple de code XAML suivant montre un ControlTemplate
pour des objets CardView
, qui utilise l’extension de balisage TemplateBinding
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BackgroundColor="{TemplateBinding CardColor}"
BorderColor="{TemplateBinding BorderColor}"
CornerRadius="5"
HasShadow="True"
Padding="8"
HorizontalOptions="Center"
VerticalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Frame IsClippedToBounds="True"
BorderColor="{TemplateBinding BorderColor}"
BackgroundColor="{TemplateBinding IconBackgroundColor}"
CornerRadius="38"
HeightRequest="60"
WidthRequest="60"
HorizontalOptions="Center"
VerticalOptions="Center">
<Image Source="{TemplateBinding IconImageSource}"
Margin="-20"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFill" />
</Frame>
<Label Grid.Column="1"
Text="{TemplateBinding CardTitle}"
FontAttributes="Bold"
FontSize="Large"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start" />
<BoxView Grid.Row="1"
Grid.ColumnSpan="2"
BackgroundColor="{TemplateBinding BorderColor}"
HeightRequest="2"
HorizontalOptions="Fill" />
<Label Grid.Row="2"
Grid.ColumnSpan="2"
Text="{TemplateBinding CardDescription}"
VerticalTextAlignment="Start"
VerticalOptions="Fill"
HorizontalOptions="Fill" />
</Grid>
</Frame>
</ControlTemplate>
</ContentPage.Resources>
...
</ContentPage>
Dans cet exemple, l’extension de balisage TemplateBinding
résout les expressions de liaison par rapport aux propriétés de chaque objet CardView
. Les captures d’écran suivantes montrent le CardViewControlTemplate
appliqué aux trois objets CardView
:
Important
L’utilisation de l’extension de balisage TemplateBinding
équivaut à affecter comme BindingContext
de l’élément racine du modèle son parent basé sur un modèle avec l’extension de balisage RelativeSource
, puis à résoudre les liaisons des objets enfants avec l’extension de balisage Binding
. En fait, l’extension de balisage TemplateBinding
crée un Binding
dont la Source
est RelativeBindingSource.TemplatedParent
.
Appliquer un ControlTemplate avec un style
Les modèles de contrôle peuvent également être appliqués avec des styles. Pour ce faire, vous devez créer un style implicite ou explicite qui consomme le ControlTemplate
.
L’exemple de code XAML suivant montre un style implicite qui consomme le CardViewControlTemplate
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
...
</ControlTemplate>
<Style TargetType="controls:CardView">
<Setter Property="ControlTemplate"
Value="{StaticResource CardViewControlTemplate}" />
</Style>
</ContentPage.Resources>
<StackLayout Margin="30">
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"/>
<controls:CardView BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png" />
</StackLayout>
</ContentPage>
Dans cet exemple, le Style
implicite est appliqué automatiquement à chaque objet CardView
, et affecte CardViewControlTemplate
comme propriété ControlTemplate
de chaque CardView
.
Pour plus d’informations sur les styles, consultez Xamarin.Forms Styles.
Redéfinir l’interface utilisateur d’un contrôle
Quand un ControlTemplate
est instancié et affecté à la propriété ControlTemplate
d’un contrôle personnalisé dérivé de ContentView
ou d’une page dérivée de ContentPage
, la structure visuelle définie pour le contrôle ou la page personnalisé est remplacée par la structure visuelle définie dans le ControlTemplate
.
Par exemple, le contrôle personnalisé CardViewUI
définit son interface utilisateur à l’aide du code XAML suivant :
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ControlTemplateDemos.Controls.CardViewUI"
x:Name="this">
<Frame BindingContext="{x:Reference this}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
CornerRadius="5"
HasShadow="True"
Padding="8"
HorizontalOptions="Center"
VerticalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Frame IsClippedToBounds="True"
BorderColor="{Binding BorderColor, FallbackValue='Black'}"
BackgroundColor="{Binding IconBackgroundColor, FallbackValue='Gray'}"
CornerRadius="38"
HeightRequest="60"
WidthRequest="60"
HorizontalOptions="Center"
VerticalOptions="Center">
<Image Source="{Binding IconImageSource}"
Margin="-20"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFill" />
</Frame>
<Label Grid.Column="1"
Text="{Binding CardTitle, FallbackValue='Card title'}"
FontAttributes="Bold"
FontSize="Large"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start" />
<BoxView Grid.Row="1"
Grid.ColumnSpan="2"
BackgroundColor="{Binding BorderColor, FallbackValue='Black'}"
HeightRequest="2"
HorizontalOptions="Fill" />
<Label Grid.Row="2"
Grid.ColumnSpan="2"
Text="{Binding CardDescription, FallbackValue='Card description'}"
VerticalTextAlignment="Start"
VerticalOptions="Fill"
HorizontalOptions="Fill" />
</Grid>
</Frame>
</ContentView>
Toutefois, les contrôles qui composent cette interface utilisateur peuvent être remplacés en définissant une nouvelle structure visuelle dans un ControlTemplate
et en l’affectant à la propriété ControlTemplate
d’un objet CardViewUI
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewCompressed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{TemplateBinding IconImageSource}"
BackgroundColor="{TemplateBinding IconBackgroundColor}"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFill"
HorizontalOptions="Center"
VerticalOptions="Center" />
<StackLayout Grid.Column="1">
<Label Text="{TemplateBinding CardTitle}"
FontAttributes="Bold" />
<Label Text="{TemplateBinding CardDescription}" />
</StackLayout>
</Grid>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout Margin="30">
<controls:CardViewUI BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewCompressed}" />
<controls:CardViewUI BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewCompressed}" />
<controls:CardViewUI BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewCompressed}" />
</StackLayout>
</ContentPage>
Dans cet exemple, la structure visuelle de l’objet CardViewUI
est redéfinie dans un ControlTemplate
qui fournit une structure visuelle plus compacte adaptée à une liste condensée :
Remplacer le contenu dans un ContentPresenter
Un ContentPresenter
peut être placé dans un modèle de contrôle afin de marquer l’emplacement où apparaîtra le contenu devant être affiché par le contrôle personnalisé basé sur un modèle ou la page basée sur un modèle. Le contrôle ou la page personnalisé qui consomme le modèle de contrôle définira ensuite le contenu devant être affiché par le ContentPresenter
. Le diagramme suivant illustre un ControlTemplate
pour une page qui contient plusieurs contrôles, notamment un ContentPresenter
marqué par un rectangle bleu :
Le code XAML suivant montre un modèle de contrôle nommé TealTemplate
qui contient un ContentPresenter
dans sa structure visuelle :
<ControlTemplate x:Key="TealTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*" />
<RowDefinition Height="0.8*" />
<RowDefinition Height="0.1*" />
</Grid.RowDefinitions>
<BoxView Color="Teal" />
<Label Margin="20,0,0,0"
Text="{TemplateBinding HeaderText}"
TextColor="White"
FontSize="Title"
VerticalOptions="Center" />
<ContentPresenter Grid.Row="1" />
<BoxView Grid.Row="2"
Color="Teal" />
<Label x:Name="changeThemeLabel"
Grid.Row="2"
Margin="20,0,0,0"
Text="Change Theme"
TextColor="White"
HorizontalOptions="Start"
VerticalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
</Label.GestureRecognizers>
</Label>
<controls:HyperlinkLabel Grid.Row="2"
Margin="0,0,20,0"
Text="Help"
TextColor="White"
Url="https://video2.skills-academy.com/xamarin/xamarin-forms/"
HorizontalOptions="End"
VerticalOptions="Center" />
</Grid>
</ControlTemplate>
L’exemple suivant montre TealTemplate
affecté à la propriété ControlTemplate
d’une page dérivée de ContentPage
:
<controls:HeaderFooterPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
ControlTemplate="{StaticResource TealTemplate}"
HeaderText="MyApp"
...>
<StackLayout Margin="10">
<Entry Placeholder="Enter username" />
<Entry Placeholder="Enter password"
IsPassword="True" />
<Button Text="Login" />
</StackLayout>
</controls:HeaderFooterPage>
Au moment de l’exécution, quand TealTemplate
est appliqué à la page, le contenu de la page est remplacé dans le ContentPresenter
défini dans le modèle de contrôle :
Obtenir un élément nommé à partir d’un modèle
Les éléments nommés dans un modèle de contrôle peuvent être récupérés à partir du contrôle personnalisé basé sur un modèle ou de la page basée sur un modèle. Ceci est possible avec la méthode GetTemplateChild
, qui retourne l’élément nommé dans l’arborescence d’éléments visuels instancié ControlTemplate
, s’il est trouvé. Sinon, null
est retourné.
Après qu’un modèle de contrôle a été instancié, la méthode du modèle OnApplyTemplate
est appelée. La méthode GetTemplateChild
doit donc être appelée à partir d’une substitution OnApplyTemplate
dans la page ou le contrôle basé sur un modèle.
Important
La méthode GetTemplateChild
doit uniquement être appelée après que la méthode OnApplyTemplate
a été appelée.
Le code XAML suivant montre un modèle de contrôle nommé TealTemplate
qui peut être appliqué à des pages dérivées de ContentPage
:
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label x:Name="changeThemeLabel"
Grid.Row="2"
Margin="20,0,0,0"
Text="Change Theme"
TextColor="White"
HorizontalOptions="Start"
VerticalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
</Label.GestureRecognizers>
</Label>
...
</Grid>
</ControlTemplate>
Dans cet exemple, l’élément Label
est nommé et peut être récupéré dans le code de la page basée sur un modèle. Cela s’effectue en appelant la méthode GetTemplateChild
à partir de la substitution OnApplyTemplate
pour la page basée sur un modèle :
public partial class AccessTemplateElementPage : HeaderFooterPage
{
Label themeLabel;
public AccessTemplateElementPage()
{
InitializeComponent();
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
themeLabel = (Label)GetTemplateChild("changeThemeLabel");
themeLabel.Text = OriginalTemplate ? "Aqua Theme" : "Teal Theme";
}
}
Dans cet exemple, l’objet Label
nommé changeThemeLabel
est récupéré une fois que le ControlTemplate
a été instancié. changeThemeLabel
est alors accessible et peut ensuite être manipulé par la classe AccessTemplateElementPage
. Les captures d’écran suivantes montrent que le texte affiché par le Label
a été modifié :
Lier à un viewmodel
Un ControlTemplate
peut lier des données à un viewmodel, même quand le ControlTemplate
est lié au parent basé sur un modèle (l’instance de l’objet d’exécution à laquelle le modèle est appliqué).
L’exemple de code XAML suivant montre une page qui utilise un viewmodel nommé PeopleViewModel
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ControlTemplateDemos"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<ContentPage.BindingContext>
<local:PeopleViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<DataTemplate x:Key="PersonTemplate">
<controls:CardView BorderColor="DarkGray"
CardTitle="{Binding Name}"
CardDescription="{Binding Description}"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</DataTemplate>
</ContentPage.Resources>
<StackLayout Margin="10"
BindableLayout.ItemsSource="{Binding People}"
BindableLayout.ItemTemplate="{StaticResource PersonTemplate}" />
</ContentPage>
Dans cet exemple, le BindingContext
de la page est défini sur une instance de PeopleViewModel
. Ce viewmodel expose une collection People
et un ICommand
nommé DeletePersonCommand
. Le StackLayout
sur la page utilise une disposition pouvant être liée afin de lier aux données dans la collection People
, et le ItemTemplate
de la disposition pouvant être liée est définie sur la ressource PersonTemplate
. Ce DataTemplate
spécifie que chaque élément de la collection People
sera affiché à l’aide d’un objet CardView
. La structure visuelle de l’objet CardView
est définie à l’aide d’un ControlTemplate
nommé CardViewControlTemplate
:
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
CornerRadius="5"
HasShadow="True"
Padding="8"
HorizontalOptions="Center"
VerticalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="{Binding CardTitle}"
FontAttributes="Bold"
FontSize="Large"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start" />
<BoxView Grid.Row="1"
BackgroundColor="{Binding BorderColor}"
HeightRequest="2"
HorizontalOptions="Fill" />
<Label Grid.Row="2"
Text="{Binding CardDescription}"
VerticalTextAlignment="Start"
VerticalOptions="Fill"
HorizontalOptions="Fill" />
<Button Text="Delete"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeletePersonCommand}"
CommandParameter="{Binding CardTitle}"
HorizontalOptions="End" />
</Grid>
</Frame>
</ControlTemplate>
Dans cet exemple, l’élément racine du ControlTemplate
est un objet Frame
. L’objet Frame
utilise l’extension de balisage RelativeSource
pour affecter le parent basé sur un modèle comme BindingContext
. Les expressions de liaison de l’objet Frame
et ses enfants sont résolues par rapport à des propriétés CardView
, en raison de l’héritage du BindingContext
à partir de l’élément Frame
racine. Les captures d’écran suivantes montrent la page qui affiche la collection People
, qui se compose de trois éléments :
Alors que les objets du ControlTemplate
lient aux propriétés sur son parent basé sur un modèle, le Button
dans le modèle de contrôle lie à son parent basé sur un modèle et au DeletePersonCommand
dans le viewmodel. Cela est dû au fait que la propriété Button.Command
redéfinit sa source de liaison pour qu’elle corresponde au contexte de liaison de l’ancêtre dont le type de contexte de liaison est PeopleViewModel
, qui est le StackLayout
. La partie Path
des expressions de liaison peut ensuite résoudre la propriété DeletePersonCommand
. Toutefois, la propriété Button.CommandParameter
ne modifie pas sa source de liaison ; au lieu de cela, elle l’hérite de son parent dans le ControlTemplate
. Ainsi, la propriété CommandParameter
est liée à la propriété CardTitle
du CardView
.
L’effet global des liaisons Button
est que quand le Button
est sollicité, le DeletePersonCommand
de la classe PeopleViewModel
est exécuté, la valeur de la propriété CardName
étant passée au DeletePersonCommand
. Cela entraîne la suppression du CardView
spécifié de la disposition pouvant être liée :
Pour plus d’informations sur les liaisons relatives, consultez Xamarin.Forms Liaisons relatives.