Partager via


Partie 2. Syntaxe XAML essentielle

XAML est principalement conçu pour instancier et initialiser des objets. Mais souvent, les propriétés doivent ê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. Ces deux besoins nécessitent les fonctionnalités de syntaxe XAML essentielles des éléments de propriété et des 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 :

  • Labelest un élément objet. Il s’agit d’un Xamarin.Forms objet exprimé en tant qu’élément XML.
  • Text, VerticalOptionsFontAttributes et FontSize 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 VerticalOptionsLayoutOptions 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 ce à quoi il ressemble :

Disposition de grille

En jugeant uniquement de la syntaxe, ces Grid.Row, Grid.Column, Grid.RowSpanet 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, , ColumnRowSpan, ou ColumnSpan.

Au lieu de cela, Grid définit quatre propriétés pouvant être liées nommées RowProperty, ColumnProperty, RowSpanPropertyet 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, GetColumnet 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 case activée erboard 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 :

Disposition absolue

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 StackLayoutobjets Gridet 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, AbsoluteLayoutet 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 LabelText. 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, Thicknessqui 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 OnPlatformPlatforms, 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 et On les OnPlatform classes, 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.