Partager via


Liaisons compilées

Parcourez l’exemple. Parcourir l'exemple

Les liaisons de données .NET Multi-platform App UI (.NET MAUI) présentent deux problèmes principaux :

  1. Aucune validation des expressions de liaison n’a lieu au moment de la compilation. À la place, les liaisons sont résolues au moment de l’exécution. Par conséquent, les liaisons non valides ne sont pas détectées avant l’exécution, lorsque l’application ne se comporte pas comme prévu ou que des messages d’erreur apparaissent.
  2. Elles ne sont pas rentables. Les liaisons sont résolues au moment de l’exécution via l’inspection (réflexion) des objets à usage général et la surcharge de cette opération varie d’une plateforme à l’autre.

Les liaisons compilées améliorent les performances de liaison de données dans les applications .NET MAUI en résolvant les expressions de liaison au moment de la compilation plutôt qu’au moment du runtime. En outre, cette validation des expressions de liaison au moment de la compilation favorise une meilleure expérience de dépannage pour les développeurs, car les liaisons non valides sont signalées comme erreurs de build.

Important

Les liaisons compilées sont requises au lieu de liaisons basées sur des chaînes dans les applications NativeAOT, et dans les applications où le découpage complet est activé. Pour plus d’informations, consultez Trim a .NET MAUI app and Native AOT deployment.

Liaisons compilées dans XAML

Pour utiliser des liaisons compilées, définissez un attribut x:DataType sur un VisualElement avec le type d’objet auquel le VisualElement et ses enfants seront liés. Il est recommandé de définir l’attribut x:DataType dans la hiérarchie d’affichage au niveau où BindingContext est défini. Cependant, cet attribut peut être redéfini à tout emplacement dans une hiérarchie d’affichage.

Important

Les liaisons compilées nécessitent l’utilisation de la compilation XAML, qui est activée par défaut dans .NET MAUI. Si vous avez désactivé la compilation XAML, vous devez l’activer. Pour plus d’informations, consultez Compilation XAML.

Pour utiliser des liaisons compilées dans XAML, l’attribut x:DataType doit être défini sur un littéral de chaîne ou un type à l’aide de l’extension de balisage x:Type. Au moment de la compilation XAML, toutes les expressions de liaison non valides seront signalées comme erreurs de build. Toutefois, le compilateur XAML signalera uniquement une erreur de build pour la première expression de liaison non valide qu’il rencontrera. Toutes les expressions de liaison valides qui sont définies sur l’objet VisualElement ou ses enfants seront compilées, que BindingContext soit défini en XAML ou dans le code. La compilation d’une expression de liaison génère du code compilé qui obtiendra une valeur d’une propriété de la source et la définira sur la propriété de la cible spécifiée dans le balisage. En outre, en fonction de l’expression de liaison, le code généré peut observer des modifications dans la valeur de la propriété source et actualiser la propriété cible, et il peut renvoyer (push) des modifications à partir de la cible vers la source.

Important

Les liaisons compilées sont désactivées pour toutes les expressions de liaison XAML qui définissent la propriété Source. Cela tient au fait que la propriété Source est toujours définie à l’aide de l’extension de balisage x:Reference, qui ne peut pas être résolue au moment de la compilation.

En outre, les liaisons compilées dans XAML ne sont actuellement pas prises en charge pour les liaisons multiples.

Par défaut, .NET MAUI ne génère pas d’avertissements de build pour les liaisons XAML qui n’utilisent pas de liaisons compilées. Toutefois, vous pouvez opter pour les avertissements de liaisons compilées générés en définissant la propriété $(MauiStrictXamlCompilation) de build sur true dans le fichier projet de votre application (*.csproj) :

<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

Par défaut, .NET MAUI génère des avertissements de build pour les liaisons XAML qui n’utilisent pas de liaisons compilées.

Pour plus d’informations sur les avertissements de liaisons compilées XAML, consultez les avertissements des liaisons compilées XAML.

Utiliser des liaisons compilées dans XAML

L’exemple suivant illustre l’utilisation de liaisons compilées entre les vues .NET MAUI et les propriétés de viewmodel :

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorSelectorPage"
             x:DataType="local:HslColorViewModel"
             Title="Compiled Color Selector">
    <ContentPage.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </ContentPage.BindingContext>
    ...
    <StackLayout>
        <BoxView Color="{Binding Color}"
                 ... />
        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />
            <Slider Value="{Binding Hue}" />
            <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
            <Slider Value="{Binding Saturation}" />
            <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
            <Slider Value="{Binding Luminosity}" />
            <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
        </StackLayout>
    </StackLayout>    
</ContentPage>

Le ContentPage instancie le HslColorViewModel et initialise la propriété Color dans les balises d’élément de propriété pour la propriété BindingContext. Le ContentPage définit également l’attribut de x:DataType en tant que type de viewmodel, ce qui indique que toutes les expressions de liaison figurant dans la hiérarchie d’affichage ContentPage seront compilées. Cela peut être vérifié en modifiant l’une des expressions de liaison pour la lier à une propriété de viewmodel inexistante, ce qui entraînera une erreur de build. Bien que cet exemple définisse l’attribut x:DataType comme un littéral de chaîne, il peut également être défini comme un type à l’aide de l’extension de balisage x:Type. Pour plus d’informations sur l’extension de balisage x:Type, consultez la section x:Type Markup Extension.

Important

L’attribut x:DataType peut être redéfini à tout emplacement dans une hiérarchie d’affichage.

Les éléments BoxView, Label et les vues Slider héritent du contexte de liaison de ContentPage. Ces vues sont toutes des cibles de liaison qui référencent les propriétés sources dans le viewmodel. Pour la propriété BoxView.Color et la propriété Label.Text, les liaisons de données sont OneWay - les propriétés dans la vue sont définies à partir des propriétés dans le viewmodel. Toutefois, la propriété Slider.Value utilise une liaison TwoWay. Cela permet à chaque Slider d’être défini à partir du viewmodel, et également au viewmodel d’être défini à partir de chaque Slider.

À la première exécution de l’application, les éléments BoxView, Label et Slider sont tous définis à partir du viewmodel basé sur la propriété de Color initiale définie lorsque le viewmodel a été instancié. Les éléments BoxView et Label sont mis à jour au fur et à mesure de la manipulation des curseurs :

Sélecteur de couleur compilé.

Pour plus d’informations sur ce sélecteur de couleur, consultez la section ViewModels et notifications de changement de propriété.

Utiliser des liaisons compilées dans XAML dans un DataTemplate

Les liaisons figurant dans un DataTemplate sont interprétées dans le contexte de l’objet basé sur le modèle. Par conséquent, lorsque vous utilisez des liaisons compilées dans un DataTemplate, le DataTemplate doit déclarer le type de son objet de données à l’aide de l’attribut x:DataType. L’échec de cette opération peut entraîner l’héritage DataTemplate d’une erreur x:DataType à partir de son étendue parente :

<ContentPage ...
             x:DataType="local:AnimalsPageViewModel">
    <!-- Binding to AnimalsPageViewModel.Animals -->
    <CollectionView ItemsSource="{Binding Animals}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <!-- incorrect: compiler thinks you want to bind to AnimalsPageViewModel.Name -->  
                <Label Text="{Binding Name}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

L’exemple suivant illustre la définition correcte de l’élément x:DataType sur un DataTemplate:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorListPage"
             Title="Compiled Color List">
    <Grid>
        ...
        <ListView x:Name="colorListView"
                  ItemsSource="{x:Static local:NamedColor.All}"
                  ... >
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:NamedColor">
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <BoxView Color="{Binding Color}"
                                     ... />
                            <Label Text="{Binding FriendlyName}"
                                   ... />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <!-- The BoxView doesn't use compiled bindings -->
        <BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
                 ... />
    </Grid>
</ContentPage>

La propriété ListView.ItemsSource est définie sur la propriété NamedColor.All statique. La classe NamedColor utilise la réflexion .NET pour énumérer tous les champs publics statiques de la classe Colors et les stocker avec leurs noms dans une collection accessible à partir de la propriété statique All. Par conséquent, l’objet ListView est rempli avec toutes les instances de NamedColor. Pour chaque élément figurant dans ListView, le contexte de liaison de l’élément est défini sur un objet NamedColor. Les éléments BoxView et Label dans l’objet ViewCell sont liés aux propriétés de NamedColor.

Notez que le DataTemplate définit l’attribut x:DataType en tant que type de NamedColor, ce qui indique que toutes les expressions de liaison figurant dans la hiérarchie d’affichage DataTemplate seront compilées. Cela peut être vérifié en modifiant les expressions de liaison à lier à une propriété de NamedColor inexistante, ce qui entraînera une erreur de build. Bien que cet exemple définisse l’attribut x:DataType comme un littéral de chaîne, il peut également être défini comme un type à l’aide de l’extension de balisage x:Type. Pour plus d’informations sur l’extension de balisage x:Type, consultez la section x:Type Markup Extension.

Lorsque l’exemple est exécuté pour la première fois, la ListView est remplie avec des instances NamedColor. Lorsqu’un élément dans ListView est sélectionné, la propriété BoxView.Color est définie sur la couleur de l’élément sélectionné dans ListView :

Liste de couleurs compilée.

La sélection d’autres éléments dans l’objet ListView met à jour la couleur de l’objet BoxView.

Compiler des liaisons qui définissent la Source propriété

Avant .NET MAUI 9, le compilateur XAML ignore la compilation des liaisons qui définissent la Source propriété au lieu du BindingContextfichier . À partir de .NET MAUI 9, ces liaisons peuvent être compilées pour tirer parti de meilleures performances d’exécution. Toutefois, cette optimisation n’est pas activée par défaut pour éviter de rompre le code d’application existant. Pour activer cette optimisation, définissez la propriété true de build dans le $(MauiEnableXamlCBindingWithSourceCompilation) fichier projet de votre application :

<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>

Vérifiez ensuite que toutes vos liaisons sont annotées avec la valeur correcte x:DataType et qu’elles n’héritent pas des types de données incorrects de leur étendue parente :

<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
  <Label Text="{Binding Value}" />
  <Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>

Remarque

Dans les cas où il existe une liaison avec un Source, mais il hérite du x:DataType parent, il peut y avoir une incompatibilité entre le x:DataType type et le type du Source. Dans ce scénario, un avertissement est généré et une liaison basée sur la réflexion qui résout le chemin de liaison au moment de l’exécution se produit.

Combiner des liaisons compilées avec des liaisons classiques dans XAML

Les expressions de liaison sont compilées uniquement pour la hiérarchie d’affichage sur laquelle l’attribut x:DataType est défini. À l’inverse, toutes les vues dans une hiérarchie sur laquelle l’attribut x:DataType n’est pas défini utiliseront des liaisons classiques. Par conséquent, il est possible de combiner des liaisons compilées et classiques sur une page. Par exemple, dans la section précédente, les vues figurant dans le DataTemplate utilisent des liaisons compilées, alors que ce n’est pas le cas du BoxView qui est défini sur la couleur sélectionnée dans l’objet ListView.

La structuration prudente des attributs x:DataType permet ainsi d’obtenir une page utilisant des liaisons compilées et classiques. Vous pouvez également redéfinir l’attribut x:DataType à tout moment dans une hiérarchie d’affichage sur null à l’aide de l’extension de balisage x:Null. Cela indique que toutes les expressions de liaison figurant dans la hiérarchie d’affichage utiliseront des liaisons classiques. L’exemple suivant illustre cette approche :

<StackLayout x:DataType="local:HslColorViewModel">
    <StackLayout.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </StackLayout.BindingContext>
    <BoxView Color="{Binding Color}"
             VerticalOptions="FillAndExpand" />
    <StackLayout x:DataType="{x:Null}"
                 Margin="10, 0">
        <Label Text="{Binding Name}" />
        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</StackLayout>   

Le StackLayout racine définit l’attribut x:DataType en tant que type HslColorViewModel, ce qui indique que toutes les expressions de liaison figurant dans la hiérarchie d’affichage StackLayout racine seront compilées. Toutefois, le StackLayout interne redéfinit l’attribut x:DataType sur null avec l’expression de balisage x:Null. Par conséquent, les expressions de liaison figurant dans le StackLayout interne utilisent des liaisons classiques. Seul l’objet BoxView, au sein de la hiérarchie d’affichage StackLayout racine, utilise des liaisons compilées.

Pour plus d'informations sur l’expression de balisage x:Null, consultez Extension de balisage x:Null.

Avertissements des liaisons compilées XAML

Le tableau suivant répertorie les avertissements du compilateur pour les liaisons compilées et comment les résoudre :

Code Message Fix
XC0022 La liaison peut être compilée pour améliorer les performances du runtime si x:DataType elle est spécifiée. Ajoutez x:DataType à votre code XAML pour spécifier le type du fichier actif BindingContext. Il est recommandé d’ajouter x:DataType à tous les éléments où le contexte de liaison change.
XC0023 La liaison peut être compilée pour améliorer les performances du runtime si x:DataType ce n’est pas explicitement null. Remplacez par x:DataType="{x:Null}" le type approprié.
Code Message
XC0022 La liaison peut être compilée pour améliorer les performances du runtime si x:DataType elle est spécifiée.

Pour corriger cet avertissement, ajoutez-y x:DataType votre code XAML pour spécifier le type du fichier actif BindingContext. Il est recommandé d’ajouter x:DataType à tous les éléments où le contexte de liaison change.
XC0023 La liaison peut être compilée pour améliorer les performances du runtime si x:DataType ce n’est pas explicitement null.

Pour corriger cet avertissement, remplacez x:DataType="{x:Null}" par le type approprié.
XC0024 La liaison peut être compilée de manière incorrecte, car l’annotation x:DataType provient d’une étendue externe. Veillez à annoter tous les DataTemplate éléments XAML avec la valeur correcte x:DataType.

Pour corriger cet avertissement, vérifiez que tous les DataTemplate éléments sont annotés avec le bon x:DataType.
XC0025 La liaison n’a pas été compilée, car elle a une propriété définie Source explicitement et une compilation de liaisons avec laquelle Source elle n’est pas activée. Envisagez d’activer cette optimisation en définissant le <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> fichier projet dans votre fichier projet et assurez-vous que la valeur correcte x:DataType est spécifiée pour cette liaison.

Pour corriger cet avertissement, activez la $(MauiEnableXamlCBindingWithSourceCompilation) propriété de build dans votre fichier projet et annotez toutes vos liaisons avec les éléments appropriés x:DataType.

Pour vous assurer que ces avertissements ne sont pas ignorés, envisagez de modifier des avertissements spécifiques pour générer des erreurs avec la propriété de $(WarningsAsErrors) build :

<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>

Pour ignorer ces avertissements, utilisez la $(NoWarn) propriété de build avec des codes d’avertissement spécifiques :

<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>

Important

XC0022 et XC0023 les avertissements sont toujours supprimés, sauf si la propriété de $(MauiStrictXamlCompilation) build est définie sur true.

Si vous définissez la $(TreatWarningsAsErrors) propriété true de build sur le fichier projet de votre application, mais que vous souhaitez ignorer certains avertissements du compilateur XAML, utilisez la $(NoWarn) propriété de build pour réduire ces avertissements ou la $(WarningsNotAsErrors) propriété de build pour réduire la gravité de certains codes spécifiques.

Par défaut, .NET MAUI génère des avertissements de build pour les liaisons XAML qui n’utilisent pas de liaisons compilées. Vous pouvez choisir des avertissements de liaisons compilées traités comme des erreurs en définissant les propriétés et $(TreatWarningsAsErrors) les propriétés true de génération dans le $(MauiStrictXamlCompilation) fichier projet de votre application (*.csproj) :

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

Remarque

Par défaut, la $(MauiStrictXamlCompilation) propriété de build est false sauf si vous publiez votre application à l’aide du découpage complet ou nativeAOT.

Liaisons compilées dans le code

Les liaisons écrites dans le code utilisent généralement des chemins de chaîne résolus au moment du runtime avec réflexion. Toutefois, la méthode d’extension SetBinding a également une surcharge qui définit des liaisons à l’aide d’un argument Func au lieu d’un chemin d’accès de chaîne :

MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);

Toutes les méthodes ne peuvent pas être utilisées pour définir une liaison compilée. L’expression doit être une expression d’accès aux propriétés simple. Les exemples suivants montrent des expressions de liaison valides et non valides :

// Valid: Property access
static (PersonViewModel vm) => vm.Name;
static (PersonViewModel vm) => vm.Address?.Street;

// Valid: Array and indexer access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
static (PersonViewModel vm) => vm.Config["Font"];

// Valid: Casts
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;

// Invalid: Method calls
static (PersonViewModel vm) => vm.GetAddress();
static (PersonViewModel vm) => vm.Address?.ToString();

// Invalid: Complex expressions
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
static (PersonViewModel vm) => $"Name: {vm.Name}";

En outre, la méthode Binding.Create définit la liaison directement sur l’objet avec un Func, et retourne l’instance de l’objet de liaison :

myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
    Bindings = new Collection<BindingBase>
    {
        Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
        Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
        Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
    },
    Converter = new StringConcatenationConverter()
});

Ces approches de liaison compilées offrent les avantages suivants :

  • Amélioration des performances de liaisons de données en résolvant les expressions de liaison au moment de la compilation plutôt qu’au moment du runtime.
  • Meilleure expérience de résolution de problèmes pour les développeurs, car les liaisons non valides sont signalées comme erreurs de build
  • IntelliSense lors de la modification.

Performances

Les liaisons compilées améliorent les performances des liaisons de données, avec des avantages variables :

  • Une liaison compilée qui utilise la notification de modification de propriété (c'est-à-dire une liaison OneWay, OneWayToSource ou TwoWay) est résolue environ 8 fois plus vite qu’une liaison classique.
  • Une liaison compilée qui n’utilise pas la notification de modification de propriété (c'est-à-dire une liaison OneTime) est résolue environ 20 fois plus vite qu’une liaison classique.
  • La définition du BindingContext sur une liaison compilée qui utilise la notification de modification de propriété (c'est-à-dire une liaison OneWay, OneWayToSource ou TwoWay) est environ 5 fois plus rapide que la définition du BindingContext sur une liaison classique.
  • La définition du BindingContext sur une liaison compilée qui n’utilise pas la notification de modification de propriété (c'est-à-dire une liaison OneTime) est environ 7 fois plus rapide que la définition du BindingContext sur une liaison classique.

Ces différences de performances peuvent être accrues sur les appareils mobiles, selon la plateforme utilisée, la version du système d’exploitation utilisé et l’appareil sur lequel l’application s’exécute.