Partager via


Xamarin.Forms Liaisons de base

Une Xamarin.Forms liaison de données lie une paire de propriétés entre deux objets, dont au moins l’un est généralement un objet d’interface utilisateur. Ces deux objets sont appelés la cible et la source :

  • La cible est l’objet (et la propriété) sur lequel la liaison de données est définie.
  • La source est l’objet (et la propriété) référencé par la liaison de données.

Cette distinction peut parfois porter à confusion : dans le cas le plus simple, les données circulent de la source vers la cible, ce qui signifie que la valeur de la propriété cible est définie à partir de la valeur de la propriété source. Toutefois, dans certains cas, les données peuvent également circuler de la cible vers la source ou dans les deux sens. Pour éviter toute confusion, n’oubliez pas que la cible est toujours l’objet sur lequel la liaison de données est définie, même si elle fournit des données au lieu d’en recevoir.

Liaisons avec un contexte de liaison

Les liaisons de données sont généralement spécifiées entièrement en XAML, mais il est intéressant de voir des liaisons de données dans le code. La page Basic Code Binding (Liaison de code élémentaire) contient un fichier XAML avec un Label et un Slider :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.BasicCodeBindingPage"
             Title="Basic Code Binding">
    <StackLayout Padding="10, 0">
        <Label x:Name="label"
               Text="TEXT"
               FontSize="48"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

L’élément Slider est défini pour une plage de 0 à 360. L’objectif de ce programme est de faire pivoter l’objet Label en manipulant l’élément Slider.

Sans liaisons de données, vous devez définir l’événement ValueChanged de l’élément Slider sur un gestionnaire d’événements qui accède à la propriété Value de l’élément Slider et définit cette valeur sur la propriété Rotation de l’objet Label. La liaison de données automatise ce travail ; le gestionnaire d’événements et le code qu’il contient ne sont plus nécessaires.

Vous pouvez définir une liaison sur une instance de n’importe quelle classe qui dérive de BindableObject et qui inclut les dérivés Element, VisualElement, View et View. La liaison est toujours définie sur l’objet cible. La liaison fait référence à l’objet source. Pour définir la liaison de données, utilisez les deux membres suivants de la classe cible :

  • La propriété BindingContext spécifie l’objet source.
  • La méthode SetBinding spécifie la propriété cible et la propriété source.

Dans cet exemple, l’objet Label est la cible de la liaison et l’élément Slider en est la source. Des modifications dans l’élément Slider source affectent la rotation de l’objet Label cible. Les données circulent de la source vers la cible.

La méthode SetBinding définie par BindableObject a un argument de type BindingBase à partir duquel la classe Binding dérive, mais d’autres méthodes SetBinding sont définies par la classe BindableObjectExtensions. Le fichier code-behind dans l’exemple Basic Code Binding utilise une méthode d’extension SetBinding plus simple à partir de cette classe.

public partial class BasicCodeBindingPage : ContentPage
{
    public BasicCodeBindingPage()
    {
        InitializeComponent();

        label.BindingContext = slider;
        label.SetBinding(Label.RotationProperty, "Value");
    }
}

L’objet Label est la cible de la liaison et constitue donc l’objet sur lequel cette propriété est définie et sur lequel la méthode est appelée. La propriété BindingContext indique la source de la liaison, à savoir l’élément Slider.

La méthode SetBinding est appelée sur la cible de la liaison, mais spécifie la propriété cible et la propriété source. La propriété cible est spécifiée en tant qu’objet BindableProperty : Label.RotationProperty. La propriété source est spécifiée en tant que chaîne et indique la propriété Value de l’élément Slider.

La méthode SetBinding révèle l’une des règles les plus importantes des liaisons de données :

La propriété cible doit reposer sur une propriété pouvant être liée.

Cette règle implique que l’objet cible doit être une instance d’une classe qui dérive de BindableObject. Consultez l’article Propriétés pouvant être liées pour obtenir une vue d’ensemble des objets et des propriétés pouvant être liés.

Il n’y a pas de règle de ce type pour la propriété source, qui est spécifiée en tant que chaîne. En interne, la réflexion est utilisée pour accéder à la propriété réelle. Dans ce cas particulier, toutefois, la propriété Value repose également sur une propriété pouvant être liée.

Le code peut être quelque peu simplifié : la propriété pouvant être liée RotationProperty est définie par VisualElement et héritée par Label et ContentPage. Par conséquent, le nom de la classe n’est pas requis dans l’appel SetBinding :

label.SetBinding(RotationProperty, "Value");

Toutefois, inclure le nom de classe permet de se rappeler de l’objet cible.

Lorsque vous manipulez l’objet Slider, l’objet Label pivote en conséquence :

Liaison de code de base

La page Basic Xaml Binding (Liaison Xaml de base) est identique à la page Basic Code Binding, si ce n’est qu’elle définit la liaison de données entière en XAML :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.BasicXamlBindingPage"
             Title="Basic XAML Binding">
    <StackLayout Padding="10, 0">
        <Label Text="TEXT"
               FontSize="80"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand"
               BindingContext="{x:Reference Name=slider}"
               Rotation="{Binding Path=Value}" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Comme dans le code, la liaison de données est définie sur l’objet cible, qui est l’objet Label. Deux extensions de balisage XAML sont impliquées. Elles sont instantanément reconnaissables à leurs accolades de délimitation :

  • L’extension de balisage x:Reference est nécessaire pour référencer l’objet source, qui est l’objet Slider nommé slider.
  • L’extension de balisage Binding lie la propriété Rotation de l’objet Label à la propriété Value de l’élément Slider.

Pour plus d’informations sur les extensions de balisage XAML, consultez l’article Extensions de balisage XAML. L’extension de balisage x:Reference est prise en charge par la classe ReferenceExtension ; Binding est prise en charge par la classe BindingExtension. Comme l’indiquent les préfixes d’espace de noms XML, x:Reference fait partie de la spécification XAML 2009, tandis qu’il Binding fait partie de Xamarin.Forms. Notez qu’aucun guillemet n’apparaît entre les accolades.

Il est facile d’oublier l’extension de balisage x:Reference lors de la définition de BindingContext. Il est courant de définir par inadvertance la propriété directement sur le nom de la source de la liaison, comme suit :

BindingContext="slider"

Mais ce n'est pas correct. Ce balisage définit la propriété BindingContext sur un objet string dont les caractères forment le mot « slider ».

Notez que la propriété source est spécifiée avec la propriété Path de BindingExtension, qui correspond à la propriété Path de la classe Binding.

Le balisage affiché dans la page Basic XAML Binding peut être simplifié : les extensions de balisage XAML telles que x:Reference et Binding peuvent avoir des attributs de propriété de contenu définis, ce qui signifie pour des extensions de balisage XAML que le nom de propriété n’a pas besoin d’apparaître. La propriété Name est la propriété de contenu de x:Reference et la propriété Path est la propriété de contenu de Binding, ce qui signifie que vous pouvez les éliminer des expressions :

<Label Text="TEXT"
       FontSize="80"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand"
       BindingContext="{x:Reference slider}"
       Rotation="{Binding Value}" />

Liaisons sans contexte de liaison

La propriété BindingContext est un composant important des liaisons de données, mais elle n’est pas toujours nécessaire. L’objet source peut être spécifié à la place dans l’appel SetBinding ou dans l’extension de balisage Binding.

Cela est illustré dans l’exemple Alternative Code Binding (Liaison de code alternative). Le fichier XAML est similaire à l’exemple Basic Code Binding, si ce n’est que l’élément Slider est défini pour contrôler la propriété Scale de l’objet Label. Pour cette raison, la Slider valeur est définie pour une plage de -2 à 2 :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.AlternativeCodeBindingPage"
             Title="Alternative Code Binding">
    <StackLayout Padding="10, 0">
        <Label x:Name="label"
               Text="TEXT"
               FontSize="40"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Minimum="-2"
                Maximum="2"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Le fichier code-behind définit la liaison avec la méthode SetBinding définie par BindableObject. L’argument est un constructeur pour la classe Binding :

public partial class AlternativeCodeBindingPage : ContentPage
{
    public AlternativeCodeBindingPage()
    {
        InitializeComponent();

        label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));
    }
}

Le constructeur Binding possède 6 paramètres, si bien que le paramètre source est spécifié avec un argument nommé. L’argument est l’élément slider.

L’exécution de ce programme peut être quelque peu surprenante :

Autre liaison de code

L’écran iOS de gauche montre à quoi ressemble l’écran lorsque la page apparaît initialement. Où est l’objet Label ?

Le problème est que l’élément Slider a une valeur initiale de 0. Par conséquent, la propriété Scale de l’objet Label est également définie sur 0, ce qui remplace sa valeur par défaut 1. Il en résulte que l’objet Label est initialement invisible. Comme la capture d’écran d’Android l’illustre, vous pouvez manipuler l’élément Slider pour faire réapparaître l’objet Label, mais sa disparition initiale est déconcertante.

Vous découvrirez dans le prochain article comment éviter ce problème en initialisant l’élément Slider à partir de la valeur par défaut de la propriété Scale.

Remarque

La classe VisualElement définit également les propriétés ScaleX et ScaleY, qui peuvent redimensionner l’élément VisualElement dans les directions horizontale et verticale.

La page Alternative XAML Binding (Liaison XAML alternative) illustre une liaison équivalente entièrement en XAML :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.AlternativeXamlBindingPage"
             Title="Alternative XAML Binding">
    <StackLayout Padding="10, 0">
        <Label Text="TEXT"
               FontSize="40"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand"
               Scale="{Binding Source={x:Reference slider},
                               Path=Value}" />

        <Slider x:Name="slider"
                Minimum="-2"
                Maximum="2"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Maintenant, l’extension de balisage Binding a deux propriétés définies, Source et Path, séparées par une virgule. Elles peuvent apparaître sur la même ligne, si vous préférez :

Scale="{Binding Source={x:Reference slider}, Path=Value}" />

La propriété Source est définie sur une extension de balisage x:Reference qui possède autrement la même syntaxe que la définition de BindingContext. Notez qu’aucun guillemet ne figure entre les accolades et que les deux propriétés doivent être séparées par une virgule.

La propriété de contenu de l’extension de balisage Binding est Path, mais la partie Path= de l’extension de balisage peut être éliminée seulement s’il s’agit de la première propriété dans l’expression. Pour éliminer la partie Path=, vous devez échanger les deux propriétés :

Scale="{Binding Value, Source={x:Reference slider}}" />

Bien que les extensions de balisage XAML soient généralement délimitées par des accolades, elles peuvent également être exprimées en tant qu’éléments objets :

<Label Text="TEXT"
       FontSize="40"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand">
    <Label.Scale>
        <Binding Source="{x:Reference slider}"
                 Path="Value" />
    </Label.Scale>
</Label>

Maintenant, les propriétés Source et Path sont des attributs XAML réguliers : les valeurs apparaissent entre guillemets et les attributs ne sont pas séparés par une virgule. L’extension de balisage x:Reference peut également devenir un élément objet :

<Label Text="TEXT"
       FontSize="40"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand">
    <Label.Scale>
        <Binding Path="Value">
            <Binding.Source>
                <x:Reference Name="slider" />
            </Binding.Source>
        </Binding>
    </Label.Scale>
</Label>

Cette syntaxe n’est pas courante, mais elle est parfois nécessaire lorsque des objets complexes sont impliqués.

Les exemples présentés jusqu'à présent définissent la propriété BindingContext et la propriété Source de Binding sur une extension de balisage x:Reference pour référencer une autre vue dans la page. Ces deux propriétés sont de type Object et elles peuvent être définies sur n’importe quel objet incluant des propriétés qui conviennent pour des sources de liaison.

Dans les articles à venir, vous découvrirez que vous pouvez définir la propriété BindingContext ou Source sur une extension de balisage x:Static pour référencer la valeur d’un champ ou d’une propriété statique, ou une extension de balisage StaticResource pour référencer un objet stocké dans un dictionnaire de ressources, ou directement sur un objet, qui est généralement (mais pas toujours) une instance d’un ViewModel.

La propriété BindingContext peut également être définie sur un objet Binding, afin que les propriétés Source et Path de Binding définissent le contexte de liaison.

Héritage du contexte de liaison

Dans cet article, vous avez vu que vous pouvez spécifier l’objet source en utilisant la propriété BindingContext ou la propriété Source de l’objet Binding. Si les deux sont définis, la propriété Source de Binding est prioritaire sur BindingContext.

La propriété BindingContext a une caractéristique extrêmement importante :

Le paramètre de la propriété BindingContext est hérité via l’arborescence d'éléments visuels.

Comme vous le verrez, cela peut être très pratique pour simplifier les expressions de liaison et, dans certains cas, en particulier dans les scénarios Model-View-ViewModel (MVVM), il est essentiel.

L’exemple Binding Context Inheritance (Héritage du contexte de liaison) est une simple illustration de l’héritage du contexte de liaison :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.BindingContextInheritancePage"
             Title="BindingContext Inheritance">
    <StackLayout Padding="10">

        <StackLayout VerticalOptions="FillAndExpand"
                     BindingContext="{x:Reference slider}">

            <Label Text="TEXT"
                   FontSize="80"
                   HorizontalOptions="Center"
                   VerticalOptions="EndAndExpand"
                   Rotation="{Binding Value}" />

            <BoxView Color="#800000FF"
                     WidthRequest="180"
                     HeightRequest="40"
                     HorizontalOptions="Center"
                     VerticalOptions="StartAndExpand"
                     Rotation="{Binding Value}" />
        </StackLayout>

        <Slider x:Name="slider"
                Maximum="360" />

    </StackLayout>
</ContentPage>

La propriété BindingContext de StackLayout est définie sur l’élément slider. Ce contexte de liaison est hérité par les deux objets Label et BoxView, qui ont tous les deux leur propriété Rotation définie sur la propriété Value de l’élément Slider :

Héritage du contexte de liaison

Dans le prochain article, vous verrez comment le mode de liaison peut modifier le flux de données entre les objets cible et source.

Retrouvez d’autres vidéos Xamarin sur Channel 9 et YouTube.