Partager via


Vue d’ensemble de la liaison de données Windows

La liaison de données dans les applications WinUI vous permet de connecter efficacement des contrôles aux sources de données. Découvrez comment lier un contrôle à un seul élément ou à une collection d’éléments, à contrôler le rendu des éléments, à implémenter des vues de détails et à mettre en forme des données pour l’affichage. Pour plus d’informations, consultez La liaison de données en profondeur.

Conditions préalables

Cette rubrique part du principe que vous savez comment créer une application WinUI de base avec le Kit de développement logiciel (SDK) d’application Windows. Pour obtenir des instructions sur la création de votre première application WinUI, consultez Créer une application WinUI.

Créer le projet

Créez une application vide WinUI, projet C# empaqueté . Nommez-le « Démarrage rapide ».

Lier à un seul élément

Chaque liaison se compose d’une cible de liaison et d’une source de liaison. En règle générale, la cible est une propriété d’un contrôle ou d’un autre élément d’interface utilisateur, et la source est une propriété d’une instance de classe (un modèle de données ou un modèle de vue). Cet exemple montre comment lier un contrôle à un seul élément. La cible est la propriété Text d’un TextBlock. La source est une instance d’une classe simple nommée Recording qui représente un enregistrement audio. Examinons d’abord la classe.

Ajoutez une nouvelle classe à votre projet et nommez la classe Recording.

namespace Quickstart
{
    public class Recording
    {
        public string ArtistName { get; set; }
        public string CompositionName { get; set; }
        public DateTime ReleaseDateTime { get; set; }
        public Recording()
        {
            ArtistName = "Wolfgang Amadeus Mozart";
            CompositionName = "Andante in C for Piano";
            ReleaseDateTime = new DateTime(1761, 1, 1);
        }
        public string OneLineSummary
        {
            get
            {
                return $"{CompositionName} by {ArtistName}, released: "
                    + ReleaseDateTime.ToString("d");
            }
        }
    }
    public class RecordingViewModel
    {
        private Recording defaultRecording = new();
        public Recording DefaultRecording { get { return defaultRecording; } }
    }
}

Ensuite, exposez la classe de source de liaison à partir de la classe qui représente votre fenêtre de balisage. Ajoutez une propriété de type RecordingViewModel à MainWindow.xaml.cs.

namespace Quickstart
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }
        public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
    }
}

La dernière étape consiste à lier un TextBlock à la propriété ViewModel.DefaultRecording.OneLineSummary.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"/>
    </Grid>
</Window>

Voici le résultat.

Capture d’écran d’une application WinUI montrant un TextBlock lié à un seul élément.

Lier à une collection d’éléments

Un scénario courant consiste à établir une liaison à une collection d’objets métier. En C#, utilisez la classe T ObservableCollection<T> générique pour la liaison de données. Il implémente l’interface INotifyCollectionChanged , qui fournit une notification de modification aux liaisons lorsque des éléments sont ajoutés ou supprimés. Toutefois, en raison d’un bogue connu du mode de publication WinUI avec .NET 8 et versions ultérieures, vous devrez peut-être utiliser une liste<T> dans certains scénarios, en particulier si votre collection est statique et ne change pas après l’initialisation. Si votre interface utilisateur doit être mise à jour lorsque la collection change au moment de l’exécution, utilisez ObservableCollection<T>. Si vous n’avez besoin d’afficher qu’un ensemble fixe d’éléments, List<T> suffit. En outre, si vous souhaitez que vos contrôles liés soient mis à jour avec des modifications apportées aux propriétés des objets de la collection, ces objets doivent implémenter INotifyPropertyChanged. Pour plus d’informations, voir Présentation détaillée de la liaison de données.

Remarque

En utilisant List<T>, vous risquez de ne pas recevoir de notifications de modification pour les modifications de collecte. Si vous devez répondre aux modifications, envisagez d’utiliser ObservableCollection<T>. Dans cet exemple, vous n’avez pas besoin de répondre aux modifications de collection, car List<T> suffit.

L’exemple suivant lie un ListView à une collection d’objets Recording . Tout d’abord, ajoutez la collection à votre modèle d’affichage. Ajoutez ces nouveaux membres à la RecordingViewModel classe.

public class RecordingViewModel
{
    ...
    private List<Recording> recordings = new();
    public List<Recording> Recordings{ get{ return recordings; } }
    public RecordingViewModel()
    {
        recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
            CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
        recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
            CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
        recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
            CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
    }
}

Ensuite, liez un ListView à la ViewModel.Recordings propriété.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <ListView ItemsSource="{x:Bind ViewModel.Recordings}"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center"/>
    </Grid>
</Window>

Vous n'avez pas encore fourni de modèle de données pour la classe Recording, c'est pourquoi le mieux que le framework de l'interface utilisateur puisse faire est d'appeler ToString pour chaque élément dans le ListView. L’implémentation par défaut de ToString retourne le nom du type.

Liaison d’un affichage liste 1

Pour résoudre ce problème, vous pouvez remplacer ToString pour retourner la valeur de OneLineSummary, ou vous pouvez fournir un modèle de données. L’option de modèle de données est une solution plus courante et flexible. Vous spécifiez un modèle de données à l’aide de la propriété ContentTemplate d’un contrôle de contenu ou de la propriété ItemTemplate d’un contrôle d’éléments. Voici deux façons de concevoir un modèle Recording de données avec une illustration du résultat.

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <TextBlock Text="{x:Bind OneLineSummary}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Liaison d’un affichage liste 2

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <StackPanel Orientation="Horizontal" Margin="6">
                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                    <TextBlock Text="{x:Bind CompositionName}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Liaison d’un affichage liste 3

Pour plus d’informations sur la syntaxe XAML, consultez Créer une interface utilisateur avec xaml. Pour plus d'informations sur la disposition du contrôle, consultez Définir des dispositions avec XAML.

Ajouter une vue de détails

Vous pouvez choisir d'afficher tous les détails des objets Recording dans les éléments ListView . Mais cette approche prend beaucoup d’espace. Au lieu de cela, vous pouvez afficher suffisamment de données dans l’élément pour l’identifier. Lorsque l’utilisateur effectue une sélection, vous pouvez afficher tous les détails de l’élément sélectionné dans une partie distincte de l’interface utilisateur appelée vue détails. Cette disposition est également appelée vue maître/détails, ou vue liste/détails.

Vous pouvez implémenter cette disposition de deux manières. Vous pouvez lier la vue des détails à la propriété SelectedItem de la ListView. Vous pouvez également utiliser une CollectionViewSource. Dans ce cas, vous liez à la fois ListView et l'affichage des détails à CollectionViewSource. Cette approche s’occupe de l’élément actuellement sélectionné pour vous. Les deux techniques sont présentées dans les sections suivantes, et elles donnent tous deux les mêmes résultats (illustrés dans l’illustration).

Remarque

Jusqu’à présent dans cette rubrique, vous n’avez utilisé que l’extension de balisage {x :Bind}. Toutefois, les deux techniques présentées dans les sections suivantes nécessitent l’extension de balisage {Binding} plus flexible (mais moins performante).

Voici tout d'abord la technique SelectedItem. Pour une application C#, la seule modification nécessaire est apportée au balisage.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Recording">
                        <StackPanel Orientation="Horizontal" Margin="6">
                            <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                            <StackPanel>
                                <TextBlock Text="{x:Bind CompositionName}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
            Margin="0,24,0,0">
                <TextBlock Text="{Binding ArtistName}"/>
                <TextBlock Text="{Binding CompositionName}"/>
                <TextBlock Text="{Binding ReleaseDateTime}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

Pour la technique CollectionViewSource, commencez par ajouter un CollectionViewSource en tant que ressource du Gridde niveau supérieur.

<Grid.Resources>
    <CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>

Remarque

La classe Window dans WinUI n’a pas de propriété Resources. Vous pouvez ajouter le CollectionViewSource à l’élément Grid de niveau supérieur (ou à d’autres éléments d’interface utilisateur parent comme StackPanel). Si vous travaillez dans un Page, vous pouvez ajouter la CollectionViewSource au Page.Resources.

Ensuite, ajustez les liaisons sur ListView (qui n’ont plus besoin d’être nommées) et dans la vue détails pour utiliser CollectionViewSource. En liant directement l’affichage des détails à l’élément actuel de CollectionViewSource, vous indiquez que vous souhaitez vous lier à l’élément courant dans les liaisons où le chemin ne peut pas être trouvé sur la collection elle-même. Il n’est pas nécessaire de préciser la propriété CurrentItem comme chemin pour la liaison, mais vous pouvez le faire pour éviter toute ambiguïté.

...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...

Et voici le résultat identique dans chaque cas.

Liaison d’un affichage liste 4

Mettre en forme ou convertir des valeurs de données pour l’affichage

Le rendu ci-dessus présente un problème. La ReleaseDateTime propriété n’est pas seulement une date ; il s’agit d’une DateTime. Il s’affiche donc avec plus de précision que vous n’en avez besoin. Une solution consiste à ajouter une propriété de chaîne à la classe Recording qui retourne l’équivalent de ReleaseDateTime.ToString("d"). Le nommage de cette propriété ReleaseDate indique qu’elle retourne une date et non une date et une heure. Le fait de le nommer ReleaseDateAsString indique en outre qu’il retourne une chaîne.

Une solution plus flexible consiste à utiliser un convertisseur de valeur. Voici un exemple de création de votre propre convertisseur de valeur. Ajoutez le code suivant à votre fichier de code source Recording.cs.

public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, string language)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Vous pouvez désormais ajouter une instance de StringFormatter en tant que ressource et l’utiliser dans la liaison de TextBlock qui affiche la propriété ReleaseDateTime.

<Grid.Resources>
    ...
    <local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
    Converter={StaticResource StringFormatterValueConverter},
    ConverterParameter=Released: \{0:d\}}"/>
...

Comme vous pouvez le constater, pour une flexibilité de mise en forme, le balisage transmet une chaîne de format au convertisseur par le biais du paramètre de convertisseur. Dans l’exemple de code présenté dans cette rubrique, le convertisseur de valeurs C# utilise ce paramètre.

Voici le résultat.

afficher une date avec une mise en forme personnalisée

Différences entre liaison et x :Bind

Lorsque vous utilisez la liaison de données dans les applications WinUI, vous pouvez rencontrer deux mécanismes de liaison principaux : Binding et x:Bind. Bien que les deux servent à connecter des éléments d’interface utilisateur à des sources de données, ils ont des différences distinctes :

  • x:Bind: offre une vérification au moment de la compilation, de meilleures performances et est fortement typée. Il est idéal pour les scénarios où vous connaissez la structure de données au moment de la compilation.
  • Binding: fournit une évaluation du runtime et est plus flexible pour les scénarios dynamiques, par exemple lorsque la structure de données n’est pas connue au moment de la compilation.

Scénarios non pris en charge par x :Bind

Bien que x:Bind soit puissant, vous ne pouvez pas l’utiliser dans certains cas :

  • Structures de données dynamiques : si la structure de données n’est pas connue au moment de la compilation, vous ne pouvez pas utiliser x:Bind.
  • Liaison d’élément à élément : x:Bind ne prend pas en charge la liaison directement entre deux éléments d’interface utilisateur.
  • La liaison à un DataContext: x:Bind n’hérite DataContext pas automatiquement d’un élément parent.
  • Liaisons bidirectionnelles avec Mode=TwoWay : bien que prise en charge, x:Bind nécessite une implémentation explicite de INotifyPropertyChanged pour chaque propriété que vous souhaitez mettre à jour lorsque la source change, qu’elle utilise une liaison unidirectionnelle ou bidirectionnelle. La principale différence avec les liaisons bidirectionnelle est que les modifications sont également transmises de l’interface utilisateur à la source.

Pour obtenir des exemples pratiques et une compréhension plus approfondie de l’utilisation de chacun d’eux, consultez les rubriques suivantes :