Vue d’ensemble de la liaison de données Windows
Cette rubrique vous montre comment lier un contrôle (ou tout autre élément d’interface utilisateur) à un seul élément, ou comment lier le contrôle d’un élément à une collection d’éléments dans une application SDK d’application Windows. Elle explique également comment contrôler le rendu des éléments, implémenter un affichage détails en fonction d’une sélection et convertir des données pour l’affichage. Pour obtenir des informations plus détaillées, consultez Présentation détaillée de la liaison de données.
Prerequisites
Dans cette rubrique, nous partons du principe que vous savez créer une application SDK d’application Windows de base. Pour obtenir des instructions sur la création de votre première application SDK d’application Windows, consultez Créer votre premier projet WinUI 3 (SDK d’application Windows).
Créer le projet
Créez un projet C# Blank App, Packaged (WinUI 3 in Desktop). Nommez-le « Quickstart ».
Liaison à un élément unique
Chaque liaison se compose d’une cible 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 d’affichage). Cet exemple montre comment lier un contrôle à un élément unique. 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 Recording();
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. Pour cela, nous ajoutons une propriété de type RecordingViewModel
à MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new RecordingViewModel();
}
public RecordingViewModel ViewModel{ get; set; }
}
}
La dernière pièce consiste à lier une 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>
Résultat :
Liaison à une collection d’éléments
Un scénario courant consiste à créer une liaison à une collection d’objets métier. En C#, la classe ObservableCollection<T> générique est un bon choix de collection pour la liaison de données, car elle implémente les interfaces INotifyPropertyChanged et INotifyCollectionChanged. Ces interfaces envoient une notification de modification aux liaisons lorsque des éléments sont ajoutés ou supprimés ou qu’une propriété de la liste est elle-même modifiée. Si vous voulez que vos contrôles liés soient mis à jour avec les modifications apportées aux propriétés des objets de la collection, l’objet métier doit également implémenter INotifyPropertyChanged
. Pour plus d’informations, voir Présentation détaillée de la liaison de données.
L’exemple suivant lie une classe ListView à une collection d’objets Recording
. Commençons par ajouter la collection à notre modèle d’affichage. Ajoutez simplement ces nouveaux membres à la classe RecordingViewModel
.
public class RecordingViewModel
{
...
private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
public ObservableCollection<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 propriété ViewModel.Recordings
.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>
Nous n’avons pas encore fourni de modèle de données pour la classe Recording
. Par conséquent, le mieux que l’infrastructure d’interface utilisateur puisse faire est d’appeler ToString pour chaque élément de ListView. L’implémentation par défaut de ToString
consiste à renvoyer le nom du type.
Pour résoudre ce problème, nous pouvons soit remplacer ToString pour retourner la valeur de OneLineSummary
, soit fournir un modèle de données. L’option de modèle de données est une solution plus habituelle et plus flexible. Pour spécifier un modèle de données, vous devez utiliser la propriété ContentTemplate d’un contrôle de contenu ou la propriété ItemTemplate d’un contrôle d’éléments. Voici deux manières de créer un modèle de données pour Recording
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>
<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>
Pour en savoir plus sur la syntaxe XAML, consultez Créer une interface utilisateur avec XAML. Pour en savoir plus sur la mise en forme de contrôle, consultez Définir des dispositions avec XAML.
Ajout d’un affichage de détails
Vous pouvez choisir d’afficher tous les détails des objets Recording
dans les éléments ListView. Cependant, l’espace occupé à l’écran sera considérable. Au lieu de cela, vous pouvez afficher juste assez de données dans l’élément à identifier puis, lorsque l’utilisateur effectue une sélection, afficher tous les détails de l’élément sélectionné dans un élément d’interface utilisateur distinct appelé affichage détails. Cette disposition est également connue sous le nom d’affichage maître/détails ou d’affichage liste/détails.
Il existe deux façons de procéder : Vous pouvez lier l’affichage de détails à la propriété SelectedItem de ListView. Vous pouvez également utiliser un CollectionViewSource, auquel cas vous liez à la fois ListView
et la vue détails à CollectionViewSource
(avec cette opération, l’élément actuellement sélectionné est automatiquement pris en charge). Ces deux techniques sont présentées ci-dessous et donnent les mêmes résultats (montrés dans l’illustration).
Notes
Jusqu’à présent, nous avons uniquement utilisé l’extension de balisage {x:Bind}, mais les deux techniques que nous allons présenter ci-dessous requièrent l’extension de balisage {Binding}, plus souple (mais moins performante).
Tout d’abord, voici la technique SelectedItem. Pour une application C#, la seule modification nécessaire est celle à apporter 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 une CollectionViewSource
comme ressource de fenêtre.
<Window.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Window.Resources>
Ensuite, réglez les liaisons sur le contrôle ListView (qui n’a plus besoin d’être nommé) et sur l’affichage de détails de manière à utiliser la classe CollectionViewSource. Notez qu’en liant l’affichage de détails directement à la classe CollectionViewSource
, vous impliquez que vous souhaitez créer une liaison à l’élément actuel dans les liaisons où le chemin est introuvable au sein même de la collection. Il est inutile de spécifier la propriété CurrentItem
en tant que chemin de la liaison, bien que vous puissiez le faire s’il existe la moindre ambiguïté.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
Et voici le résultat identique dans chacun des cas.
Mise en forme ou conversion des valeurs de données pour l’affichage
Il y a un problème avec le rendu ci-dessus. La propriété ReleaseDateTime
n’est pas seulement une date, mais une DateTime. Ainsi, nous obtenons plus d’informations que nécessaire. Une solution consiste à ajouter à la classe Recording
une propriété de chaîne qui retourne l’équivalent de ReleaseDateTime.ToString("d")
. Nommer cette propriété ReleaseDate
indiquerait qu’elle retourne une date, et non pas une date/heure. Nommer cette propriété ReleaseDateAsString
indiquerait en plus qu’elle renvoie une chaîne.
Une solution plus souple consiste à utiliser un élément connu sous le nom de convertisseur de valeurs. Voici un exemple montrant comment créer votre propre convertisseur de valeurs. Ajoutez le code ci-dessous à 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();
}
}
À présent, nous pouvons ajouter une instance de StringFormatter
comme ressource de page et l’utiliser dans la liaison du TextBlock
qui affiche la propriété ReleaseDateTime
.
<Window.Resources>
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Window.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Comme vous pouvez le voir ci-dessus, pour une mise en forme plus souple, nous utilisons le balisage pour passer une chaîne de format dans le 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.
Résultat :
Voir aussi
Windows developer