Partie 2. Syntaxe XAML essentielle
XAML est principalement conçu pour instancier et initialiser des objets. Cependant, les propriétés doivent souvent être définies sur des objets complexes qui ne peuvent pas facilement être représentés en tant que chaînes XML, et parfois les propriétés définies par une classe doivent être définies sur une classe enfant. Dans ces deux cas, les fonctionnalités de syntaxe XAML essentielle sont nécessaires pour les éléments de propriété et les propriétés jointes.
Éléments de propriété
En XAML, les propriétés des classes sont normalement définies en tant qu’attributs XML :
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large"
TextColor="Aqua" />
Toutefois, il existe une autre façon de définir une propriété en XAML. Pour essayer cette alternative avec TextColor
, commencez par supprimer le paramètre existant TextColor
:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />
Ouvrez la balise d’élément Label
vide en la séparant en balises de début et de fin :
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
</Label>
Dans ces balises, ajoutez des balises de début et de fin qui se composent du nom de la classe et d’un nom de propriété séparés par un point :
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
</Label.TextColor>
</Label>
Définissez la valeur de la propriété comme contenu de ces nouvelles balises, comme suit :
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Ces deux façons de spécifier la TextColor
propriété sont fonctionnellement équivalentes, mais n’utilisent pas les deux méthodes pour la même propriété, car cela serait effectivement définir la propriété deux fois, et peut être ambigu.
Avec cette nouvelle syntaxe, une terminologie pratique peut être introduite :
Label
est un élément objet. Il s’agit d’un Xamarin.Forms objet exprimé en tant qu’élément XML.Text
,VerticalOptions
FontAttributes
etFontSize
sont des attributs de propriété. Elles sont Xamarin.Forms exprimées en tant qu’attributs XML.- Dans cet extrait final,
TextColor
est devenu un élément de propriété. Il s’agit d’une Xamarin.Forms propriété, mais il s’agit maintenant d’un élément XML.
La définition des éléments de propriété peut d’abord sembler une violation de la syntaxe XML, mais ce n’est pas le cas. La période n’a aucune signification particulière en XML. Pour un décodeur XML, Label.TextColor
il s’agit simplement d’un élément enfant normal.
En XAML, toutefois, cette syntaxe est très spéciale. L’une des règles des éléments de propriété est que rien d’autre ne peut apparaître dans la Label.TextColor
balise. La valeur de la propriété est toujours définie comme contenu entre les balises de début et de fin de l’élément de propriété.
Vous pouvez utiliser la syntaxe d’élément de propriété sur plusieurs propriétés :
<Label Text="Hello, XAML!"
VerticalOptions="Center">
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Vous pouvez également utiliser la syntaxe d’élément de propriété pour toutes les propriétés :
<Label>
<Label.Text>
Hello, XAML!
</Label.Text>
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
<Label.VerticalOptions>
Center
</Label.VerticalOptions>
</Label>
Au début, la syntaxe d’élément de propriété peut sembler un remplacement inutile long-winded pour quelque chose relativement simple, et dans ces exemples, c’est certainement le cas.
Toutefois, la syntaxe d’élément de propriété devient essentielle lorsque la valeur d’une propriété est trop complexe pour être exprimée sous la forme d’une chaîne simple. Dans les balises d’élément de propriété, vous pouvez instancier un autre objet et définir ses propriétés. Par exemple, vous pouvez définir explicitement une propriété telle qu’une VerticalOptions
LayoutOptions
valeur avec des paramètres de propriété :
<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>
Autre exemple : les Grid
deux propriétés nommées RowDefinitions
et ColumnDefinitions
. Ces deux propriétés sont de type RowDefinitionCollection
et ColumnDefinitionCollection
, qui sont des collections d’objets et ColumnDefinition
des RowDefinition
collections. Vous devez utiliser la syntaxe de l’élément de propriété pour définir ces collections.
Voici le début du fichier XAML d’une GridDemoPage
classe, affichant les balises d’élément de propriété pour les collections et ColumnDefinitions
les RowDefinitions
collections :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
...
</Grid>
</ContentPage>
Notez la syntaxe abrégée pour définir des cellules de taille automatique, des cellules de largeurs et de hauteurs de pixels et des paramètres d’étoile.
Propriétés attachées
Vous venez de constater que les Grid
éléments de propriété requis pour les collections et ColumnDefinitions
les RowDefinitions
lignes doivent définir les lignes et les colonnes. Toutefois, il doit également y avoir un moyen pour le programmeur d’indiquer la ligne et la colonne où réside chaque enfant du programmeur Grid
.
Dans la balise pour chaque enfant de l’enfant Grid
que vous spécifiez la ligne et la colonne de cet enfant à l’aide des attributs suivants :
Grid.Row
Grid.Column
Les valeurs par défaut de ces attributs sont 0. Vous pouvez également indiquer si un enfant s’étend sur plusieurs lignes ou colonnes avec ces attributs :
Grid.RowSpan
Grid.ColumnSpan
Ces deux attributs ont des valeurs par défaut de 1.
Voici le fichier GridDemoPage.xaml complet :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="Autosized cell"
Grid.Row="0" Grid.Column="0"
TextColor="White"
BackgroundColor="Blue" />
<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />
<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />
<Label Text="Leftover space"
Grid.Row="1" Grid.Column="1"
TextColor="Purple"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two rows (or more if you want)"
Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
TextColor="Yellow"
BackgroundColor="Blue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two columns"
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
TextColor="Blue"
BackgroundColor="Yellow"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Fixed 100x100"
Grid.Row="2" Grid.Column="2"
TextColor="Aqua"
BackgroundColor="Red"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</Grid>
</ContentPage>
Les Grid.Row
paramètres de Grid.Column
0 ne sont pas obligatoires, mais sont généralement inclus à des fins de clarté.
Voici à quoi elle ressemble :
En jugeant uniquement de la syntaxe, ces Grid.Row
, Grid.Column
, Grid.RowSpan
et Grid.ColumnSpan
attributs semblent être des champs statiques ou des propriétés de Grid
, mais assez intéressant, Grid
ne définit rien nommé Row
, , Column
RowSpan
, ou ColumnSpan
.
Au lieu de cela, Grid
définit quatre propriétés pouvant être liées nommées RowProperty
, ColumnProperty
, RowSpanProperty
et ColumnSpanProperty
. Il s’agit de types spéciaux de propriétés pouvant être liées appelées propriétés jointes. Ils sont définis par la Grid
classe mais définis sur les enfants du Grid
.
Lorsque vous souhaitez utiliser ces propriétés jointes dans le code, la Grid
classe fournit des méthodes statiques nommées SetRow
, GetColumn
et ainsi de suite. Toutefois, en XAML, ces propriétés jointes sont définies en tant qu’attributs dans les enfants de l’utilisation Grid
de noms de propriétés simples.
Les propriétés jointes sont toujours reconnaissables dans les fichiers XAML en tant qu’attributs contenant une classe et un nom de propriété séparés par un point. Elles sont appelées propriétés jointes, car elles sont définies par une classe (dans ce cas, Grid
) mais attachées à d’autres objets (dans ce cas, enfants du Grid
). Pendant la disposition, il Grid
peut interroger les valeurs de ces propriétés jointes pour savoir où placer chaque enfant.
La AbsoluteLayout
classe définit deux propriétés jointes nommées LayoutBounds
et LayoutFlags
. Voici un modèle de checkerboard réalisé à l’aide des caractéristiques de positionnement et de dimensionnement proportionnels de AbsoluteLayout
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.AbsoluteDemoPage"
Title="Absolute Demo Page">
<AbsoluteLayout BackgroundColor="#FF8080">
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
</ContentPage>
Voici :
Pour quelque chose comme cela, vous pouvez vous interroger sur la sagesse de l’utilisation de XAML. Certes, la répétition et la régulière du rectangle suggèrent qu’il pourrait être mieux réalisé dans le LayoutBounds
code.
C’est certainement une préoccupation légitime, et il n’y a aucun problème avec l’équilibrage de l’utilisation du code et du balisage lors de la définition de vos interfaces utilisateur. Il est facile de définir certains des visuels en XAML, puis d’utiliser le constructeur du fichier code-behind pour ajouter d’autres visuels qui peuvent être mieux générés dans des boucles.
Propriétés de contenu
Dans les exemples précédents, les StackLayout
objets Grid
et AbsoluteLayout
les objets sont définis sur la Content
propriété du ContentPage
, et les enfants de ces dispositions sont en fait des éléments dans la Children
collection. Pourtant, ces propriétés et Children
ces Content
propriétés ne se trouvent nulle part dans le fichier XAML.
Vous pouvez certainement inclure les propriétés et Children
les Content
propriétés en tant qu’éléments de propriété, comme dans l’exemple XamlPlusCode :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="valueLabel"
Text="A simple Label"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>
La vraie question est : Pourquoi ces éléments de propriété ne sont-ils pas requis dans le fichier XAML ?
Les éléments définis en Xamarin.Forms vue d’une utilisation en XAML sont autorisés à avoir un indicateur de propriété dans l’attribut ContentProperty
sur la classe. Si vous recherchez la classe dans la ContentPage
documentation en ligne Xamarin.Forms , cet attribut s’affiche :
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
Cela signifie que les Content
balises d’élément de propriété ne sont pas requises. Tout contenu XML qui apparaît entre les balises de début et de fin ContentPage
est supposé être affecté à la Content
propriété.
StackLayout
, Grid
, AbsoluteLayout
et RelativeLayout
tous dérivent , Layout<View>
et si vous recherchez Layout<T>
dans la Xamarin.Forms documentation, vous verrez un autre ContentProperty
attribut :
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
Cela permet au contenu de la disposition d’être automatiquement ajouté à la Children
collection sans balises d’élément de propriété explicites Children
.
D’autres classes ont également des ContentProperty
définitions d’attributs. Par exemple, la propriété de contenu est Label
Text
. Consultez la documentation de l’API pour d’autres personnes.
Différences de plateforme avec OnPlatform
Dans les applications monopage, il est courant de définir la Padding
propriété sur la page pour éviter de remplacer la barre d’état iOS. Dans le code, vous pouvez utiliser la Device.RuntimePlatform
propriété à cet effet :
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}
Vous pouvez également faire quelque chose de similaire en XAML à l’aide des classes et On
des OnPlatform
classes. Commencez par inclure des éléments de propriété pour la Padding
propriété en haut de la page :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
</ContentPage.Padding>
...
</ContentPage>
Dans ces balises, incluez une OnPlatform
balise. OnPlatform
est une classe générique. Vous devez spécifier l’argument de type générique, dans ce cas, Thickness
qui est le type de Padding
propriété. Heureusement, il existe un attribut XAML spécifiquement pour définir des arguments génériques appelés x:TypeArguments
. Cela doit correspondre au type de la propriété que vous définissez :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
OnPlatform
a une propriété nommée Platforms
qui est un IList
objet On
. Utilisez des balises d’élément de propriété pour cette propriété :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Ajoutez maintenant des On
éléments. Pour chacun d’eux, définissez la Platform
propriété et la Value
propriété sur le balisage de la Thickness
propriété :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Ce balisage peut être simplifié. La propriété de contenu est OnPlatform
Platforms
, de sorte que ces balises d’élément de propriété peuvent être supprimées :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
La Platform
propriété de On
type est de type IList<string>
, vous pouvez donc inclure plusieurs plateformes si les valeurs sont identiques :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android, UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Étant donné que Android et UWP sont définis sur la valeur par défaut de Padding
, cette balise peut être supprimée :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Il s’agit de la méthode standard pour définir une propriété dépendante de Padding
la plateforme en XAML. Si le Value
paramètre ne peut pas être représenté par une seule chaîne, vous pouvez définir des éléments de propriété pour celui-ci :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS">
<On.Value>
0, 20, 0, 0
</On.Value>
</On>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Remarque
L’extension OnPlatform
de balisage peut également être utilisée en XAML pour personnaliser l’apparence de l’interface utilisateur par plateforme. Il fournit les mêmes fonctionnalités que les classes OnPlatform
et On
, mais avec une représentation plus concise. Pour plus d’informations, consultez l’extension de balisage OnPlatform.
Résumé
Avec les éléments de propriété et les propriétés jointes, une grande partie de la syntaxe XAML de base a été établie. Toutefois, vous devez parfois définir des propriétés sur des objets de manière indirecte, par exemple à partir d’un dictionnaire de ressources. Cette approche est abordée dans la partie suivante, partie 3. Extensions de balisage XAML.