Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article décrit les fonctionnalités de liaison de données WinUI à l’aide des API de l’espace de noms Microsoft.UI.Xaml.Data.
Note
Cette rubrique décrit en détail les fonctionnalités de liaison de données. Pour une brève présentation pratique, consultez la vue d’ensemble de la liaison de données.
API importantes
Présentation
La liaison de données est une technique qui permet à l’interface utilisateur de votre application d’afficher et de synchroniser efficacement les données. En séparant les problèmes de données des problèmes d’interface utilisateur, il simplifie la conception de l’application, améliore la lisibilité et améliore la facilité de maintenance.
Vous pouvez utiliser la liaison de données pour afficher simplement des valeurs à partir d’une source de données lorsque l’interface utilisateur est affichée pour la première fois, mais pas pour répondre aux modifications apportées à ces valeurs. Ce mode de liaison est appelé à usage unique et fonctionne bien pour une valeur qui ne change pas pendant l’exécution. Vous pouvez également choisir d'« observer » les valeurs et de mettre à jour l’interface utilisateur lorsqu’elle change. Ce mode est appelé unidirectionnel et fonctionne bien pour les données en lecture seule. En fin de compte, vous pouvez choisir d’observer et de mettre à jour, afin que les modifications apportées par l’utilisateur aux valeurs de l’interface utilisateur soient automatiquement renvoyées dans la source de données. Ce mode est appelé bidirectionnel et fonctionne bien pour les données en lecture-écriture. Voici quelques exemples.
- Vous pouvez utiliser le mode unique pour lier une image à la photo de l’utilisateur actuel.
- Vous pouvez utiliser le mode unidirectionnel pour lier un ListView à une collection d’articles d’actualités en temps réel regroupés par section de journal.
- Vous pouvez utiliser le mode bidirectionnel pour lier un TextBox au nom d’un client dans un formulaire.
Indépendamment du mode, il existe deux types de liaisons et vous déclarez généralement les deux dans le balisage de l’interface utilisateur. Vous pouvez choisir d’utiliser l’extension de balisage {x :Bind} ou l’extension de balisage {Binding}. Vous pouvez même utiliser un mélange des deux dans la même application, même sur le même élément d’interface utilisateur.
{x:Bind} a été nouveau dans UWP pour Windows 10 et il a de meilleures performances. Tous les détails décrits dans cette rubrique s’appliquent aux deux types de liaison, sauf indication explicite.
Exemples d’applications UWP qui illustrent {x :Bind}
Exemples d’applications UWP qui illustrent {Binding}
- Téléchargez l’application UWP Bookstore1 .
- Téléchargez l’application Bookstore2 .
Chaque liaison implique ces éléments
- Source de liaison. Cette source fournit les données de la liaison. Il peut s’agir d’une instance de n’importe quelle classe qui a des membres dont vous souhaitez afficher les valeurs dans votre interface utilisateur.
- Cible de liaison. Cette cible est une DependencyProperty d'un FrameworkElement dans votre interface utilisateur, lequel affiche les données.
- Objet de liaison. Cet objet transfère les valeurs de données de la source à la cible, et éventuellement de la cible à la source. L’objet de liaison est créé au moment du chargement XAML à partir de votre extension de balisage {x :Bind} ou {Binding} .
Dans les sections suivantes, vous allez examiner de plus près la source de liaison, la cible de liaison et l’objet de liaison. Les sections sont liées avec l’exemple de liaison du contenu d’un bouton à une propriété de chaîne nommée NextButtonText, qui appartient à une classe nommée HostViewModel.
Source de liaison
Voici une implémentation de base d’une classe que vous pouvez utiliser comme source de liaison.
public class HostViewModel
{
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText { get; set; }
}
Cette implémentation de HostViewModel, et sa propriété NextButtonText, fonctionnent uniquement pour une liaison à usage unique. Mais les liaisons unidirectionnelles et bidirectionnelles sont extrêmement courantes. Dans ces types de liaison, l’interface utilisateur est automatiquement mise à jour en réponse aux modifications apportées aux valeurs de données de la source de liaison. Pour que ces types de liaison fonctionnent correctement, vous devez rendre votre source de liaison observable sur l’objet de liaison. Ainsi, dans notre exemple, si vous souhaitez établir une liaison unidirectionnelle ou bidirectionnelle à la NextButtonText propriété, toutes les modifications qui se produisent au moment de l’exécution vers la valeur de cette propriété doivent être observables à l’objet de liaison.
Pour ce faire, vous pouvez dériver la classe qui représente votre source de liaison à partir de DependencyObject et exposer une valeur de données par le biais d’un DependencyProperty*. C’est ainsi qu’un FrameworkElement devient observable. A FrameworkElement est une bonne source de liaison juste à l’extérieur de la boîte.
Un moyen plus léger de rendre une classe observable et nécessaire pour les classes qui ont déjà une classe de base consiste à implémenter System.ComponentModel.INotifyPropertyChanged. Cette approche implique l’implémentation d’un événement unique nommé PropertyChanged. Un exemple d’utilisation HostViewModel est illustré dans le code suivant.
...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
private string nextButtonText;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText
{
get { return nextButtonText; }
set
{
nextButtonText = value;
OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Maintenant, la NextButtonText propriété est observable. Lorsque vous créez une liaison unidirectionnelle ou bidirectionnelle à cette propriété (nous allons montrer comment plus tard), l’objet de liaison résultant s’abonne à l’événement PropertyChanged . Lorsque cet événement est déclenché, le gestionnaire de l’objet de liaison reçoit un argument contenant le nom de la propriété qui a changé. C'est ainsi que l'objet de liaison détermine quelle valeur de propriété lire à nouveau.
Ainsi, vous n’avez pas besoin d’implémenter le modèle affiché plusieurs fois précédemment, si vous utilisez C#, vous pouvez dériver de la BindableBase classe de base que vous trouverez dans l’exemple QuizGame (dans le dossier « Common »). Voici un exemple de la façon dont cela ressemble.
public class HostViewModel : BindableBase
{
private string nextButtonText;
public HostViewModel()
{
NextButtonText = "Next";
}
public string NextButtonText
{
get { return nextButtonText; }
set { SetProperty(ref nextButtonText, value); }
}
}
Déclencher l’événement PropertyChanged avec un argument String.Empty ou null indique que toutes les propriétés non indexeur de l’objet doivent être réécrites. Vous pouvez déclencher l’événement pour indiquer que les propriétés de l’indexeur sur l’objet ont changé en utilisant un argument « Item[indexer] » pour des indexeurs spécifiques (où l’indexeur est la valeur d’index) ou une valeur de « Item[] » pour tous les indexeurs.
Vous pouvez traiter une source de liaison en tant qu’objet unique dont les propriétés contiennent des données ou comme une collection d’objets. Dans le code C#, vous pouvez établir une liaison unique à un objet qui implémente List<T> pour afficher une collection qui ne change pas au moment de l’exécution. Pour une collection observable (afin d'observer quand des éléments sont ajoutés et supprimés de la collection), effectuez une liaison unidirectionnelle avec ObservableCollection<T> à la place. Pour établir une liaison à vos propres classes de collection, utilisez les instructions du tableau suivant.
| Scénario | C# (CLR) | C++/WinRT |
|---|---|---|
| Lier à un objet. | Peut être n’importe quel objet. | Peut être n’importe quel objet. |
| Obtenir des notifications de modification de propriété à partir d’un objet lié. | L’objet doit implémenter INotifyPropertyChanged. | L’objet doit implémenter INotifyPropertyChanged. |
| Lier à une collection. | Liste<T> | IVector de IInspectable ou IBindableObservableVector. Consultez les contrôles d’éléments XAML ; liez-vous à une collection C++/WinRT et à des collections avec C++/WinRT. |
| Obtenir des notifications de modification de collection à partir d’une collection liée. | ObservableCollection<T> | IObservableVector de IInspectable. Par exemple, winrt ::single_threaded_observable_vector<T>. |
| Implémentez une collection qui prend en charge la liaison. | Étendez List<T> ou implémentez IList, IList<Object>, IEnumerable ou IEnumerable<Object>. Liaison à un générique IList<T> et IEnumerable<T> n’est pas prise en charge. |
Implémentez IVector de IInspectable. Consultez les contrôles d’éléments XAML ; liez-vous à une collection C++/WinRT et à des collections avec C++/WinRT. |
| Implémentez une collection qui prend en charge les notifications de modification de regroupement. | Étendez ObservableCollection<T> ou implémentez (non générique) IList et INotifyCollectionChanged. | Implémentez IObservableVector de IInspectable ou IBindableObservableVector. |
| Implémentez une collection qui prend en charge le chargement incrémentiel. | Étendez ObservableCollection<T> ou implémentez (non générique) IList et INotifyCollectionChanged. En outre, implémentez ISupportIncrementalLoading. | Implémentez IObservableVector de IInspectable ou IBindableObservableVector. En outre, implémentez ISupportIncrementalLoading |
Vous pouvez lier des contrôles de liste à des sources de données arbitrairement volumineuses et obtenir des performances élevées en utilisant le chargement incrémentiel. Par exemple, vous pouvez lier des contrôles de liste aux résultats de requête d’images Bing sans avoir à charger tous les résultats en même temps. Au lieu de cela, vous chargez uniquement quelques résultats immédiatement et chargez des résultats supplémentaires si nécessaire. Pour prendre en charge le chargement incrémentiel, vous devez implémenter ISupportIncrementalLoading sur une source de données qui prend en charge les notifications de modification de collecte. Lorsque le moteur de liaison de données demande plus de données, votre source de données doit effectuer les requêtes appropriées, intégrer les résultats, puis envoyer les notifications appropriées pour mettre à jour l’interface utilisateur.
Cible de liaison
Dans les deux exemples suivants, la Button.Content propriété est la cible de liaison. Sa valeur est définie sur une extension de balisage qui déclare l’objet de liaison. Le premier exemple montre {x :Bind}, et le deuxième exemple montre {Binding}. La déclaration de liaisons dans le balisage est courant, car cela est pratique, lisible et compatible avec des outils. Toutefois, si vous avez besoin de le faire, vous pouvez éviter le balisage et créer impérativement (par programme) une instance de la classe Binding à la place.
<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />
Si vous utilisez C++/WinRT, vous devez ajouter l’attribut BindableAttribute à n’importe quelle classe runtime avec laquelle vous souhaitez utiliser l’extension de balisage {Binding} .
Important
Si vous utilisez C++/WinRT, l’attribut BindableAttribute est disponible avec le Kit de développement logiciel (SDK) d’application Windows. Sans cet attribut, vous devez implémenter les interfaces ICustomPropertyProvider et ICustomProperty pour pouvoir utiliser l’extension de balisage {Binding} .
Objet de liaison déclaré à l’aide de {x :Bind}
Avant de créer votre balisage {x :Bind} , vous devez exposer votre classe source de liaison à partir de la classe qui représente votre page de balisage. Ajoutez une propriété (de type HostViewModel dans ce cas) à votre MainWindow classe de fenêtre.
namespace DataBindingInDepth
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new HostViewModel();
}
public HostViewModel ViewModel { get; set; }
}
}
Après avoir ajouté la propriété, vous pouvez analyser plus en détail le balisage qui définit l'objet de liaison. L’exemple suivant utilise la même Button.Content cible de liaison que celle que vous avez vue dans la section « Cible de liaison » plus haut. Elle montre que la cible de liaison est liée à la propriété HostViewModel.NextButtonText.
<!-- MainWindow.xaml -->
<Window x:Class="DataBindingInDepth.MainWindow" ... >
<Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Window>
Notez la valeur que vous spécifiez pour Path. La fenêtre interprète cette valeur dans son propre contexte. Dans ce cas, le chemin commence par référencer la ViewModel propriété que vous venez d’ajouter à la MainWindow page. Cette propriété retourne une instance HostViewModel, vous permettant donc d'utiliser la notation par point pour accéder à la propriété HostViewModel.NextButtonText de cet objet. Vous spécifiez Mode pour remplacer la valeur par défaut {x:Bind} de type "one-time".
La propriété Path prend en charge diverses options de syntaxe pour la liaison à des propriétés imbriquées, des propriétés jointes et des indexeurs de chaînes et entiers. Pour plus d’informations, consultez la syntaxe property-path. La liaison à des indexeurs de chaîne vous donne l’effet de la liaison à des propriétés dynamiques sans avoir à implémenter ICustomPropertyProvider. Pour d’autres paramètres, consultez l’extension de balisage {x :Bind}.
Pour illustrer que la HostViewModel.NextButtonText propriété est observable, ajoutez un gestionnaire d’événements Click au bouton et mettez à jour la valeur de HostViewModel.NextButtonText. Générez, exécutez et cliquez sur le bouton pour afficher la valeur de la mise à jour du Content bouton.
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel.NextButtonText = "Updated Next button text";
}
Note
Les modifications apportées à TextBox.Text sont envoyées à une source liée bidirectionnelle lorsque le TextBox perd le focus, et non après chaque séquence de touches utilisateur.
DataTemplate et x :DataType
À l’intérieur d’un DataTemplate (que vous l’utilisiez en tant que modèle d’élément, modèle de contenu ou modèle d’en-tête), la valeur de Path n’est pas interprétée dans le contexte de la fenêtre. Au lieu de cela, il fonctionne dans le contexte de l’objet de données que vous créez. Lorsque vous utilisez {x:Bind} dans un modèle de données, vous pouvez valider ses liaisons au moment de la compilation et générer du code efficace pour ces liaisons. Pour ce faire, le DataTemplate doit déclarer le type de ses objets de données à l’aide de x:DataType. L’exemple suivant peut être utilisé comme ItemTemplate pour un contrôle d’éléments lié à une collection d’objets SampleDataGroup.
<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
<StackPanel Orientation="Vertical" Height="50">
<TextBlock Text="{x:Bind Title}"/>
<TextBlock Text="{x:Bind Description}"/>
</StackPanel>
</DataTemplate>
Objets faiblement typés dans votre chemin d’accès
Supposons que vous avez un type nommé SampleDataGroup qui implémente une propriété de chaîne nommée Title. Vous avez également une propriété MainWindow.SampleDataGroupAsObject de type object, mais retourne réellement une instance de SampleDataGroup. La liaison <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> génère une erreur de compilation, car la Title propriété n’est pas trouvée sur le type object. Pour corriger cette erreur, ajoutez un cast à votre Path syntaxe comme suit : <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Voici un autre exemple où Element est déclaré comme object mais est en fait un TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. Un cast résout le problème : <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.
Si vos données sont chargées de manière asynchrone
Les classes partielles de vos fenêtres génèrent du code pour prendre en charge {x:Bind} au moment de la compilation. Vous pouvez trouver ces fichiers dans votre obj dossier, avec des noms tels que (pour C#). <view name>.g.cs Le code généré inclut un gestionnaire pour l’événement De chargement de votre fenêtre. Ce gestionnaire appelle la Initialize méthode sur une classe générée qui représente les liaisons de votre fenêtre.
Initialize appels Update pour commencer à déplacer des données entre la source de liaison et la cible.
Loading est déclenché juste avant la première passe de mesure de la fenêtre ou du contrôle utilisateur. Si vos données se chargent de manière asynchrone, il se peut qu’elles ne soient pas prêtes au moment Initialize de l’appel. Après avoir chargé des données, vous pouvez forcer l’initialisation des liaisons ponctuelles en appelant this.Bindings.Update();. Si vous n’avez besoin que de liaisons ponctuelles pour les données chargées de manière asynchrone, il est beaucoup moins cher de les initialiser de cette façon que d’avoir des liaisons unidirectionnelle et d’écouter les modifications. Si vos données ne subissent pas de modifications affinées et sont susceptibles d’être mises à jour dans le cadre d’une action spécifique, vous pouvez effectuer vos liaisons une seule fois et forcer une mise à jour manuelle à tout moment avec un appel à Update.
Note
{x:Bind} n’est pas adapté aux scénarios à liaison tardive, tels que la navigation dans la structure du dictionnaire d’un objet JSON, ni au typage dynamique. « Tapage de canard » est une forme faible de frappe basée sur des correspondances lexicales sur les noms de propriétés (comme dans , « si elle marche, nage et c’est comme un canard, puis c’est un canard »). Avec la saisie de canard, une liaison à la Age propriété serait également satisfaite d’un Person ou d’un Wine objet (en supposant que ces types avaient chacune une Age propriété). Pour ces scénarios, utilisez l’extension de {Binding} balisage.
Objet de liaison déclaré à l’aide de {Binding}
Si vous utilisez C++/WinRT, ajoutez l’attribut BindableAttribute à toute classe runtime à laquelle vous souhaitez établir une liaison lorsque vous utilisez l’extension de balisage {Binding} . Pour utiliser {x :Bind}, vous n’avez pas besoin de cet attribut.
// HostViewModel.idl
// Add this attribute:
[Microsoft.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
HostViewModel();
String NextButtonText;
}
Important
Si vous utilisez C++/WinRT, l’attribut BindableAttribute est disponible avec le Kit de développement logiciel (SDK) d’application Windows. Sans cet attribut, vous devez implémenter les interfaces ICustomPropertyProvider et ICustomProperty pour pouvoir utiliser l’extension de balisage {Binding} .
Par défaut, {Binding} suppose que vous effectuez une liaison à DataContext de votre fenêtre de balisage. Donc, définissez la propriété DataContext de votre fenêtre pour qu'elle soit une instance de votre classe source de liaison (de type HostViewModel dans ce cas). L’exemple suivant montre le balisage qui déclare l’objet de liaison. Il utilise la même Button.Content cible de liaison que celle utilisée dans la section « Cible de liaison » plus haut, et elle est liée à la HostViewModel.NextButtonText propriété.
<Window xmlns:viewmodel="using:DataBindingInDepth" ... >
<Window.DataContext>
<viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
</Window.DataContext>
...
<Button Content="{Binding Path=NextButtonText}" ... />
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
viewModelInDataContext.NextButtonText = "Updated Next button text";
}
Notez la valeur spécifiée pour Path.
DataContext de la fenêtre interprète cette valeur, qui, dans cet exemple, est définie sur une instance de HostViewModel. Le chemin fait référence à la HostViewModel.NextButtonText propriété. Vous pouvez omettre Mode, car le comportement par défaut unidirectionnel de {Binding} fonctionne ici.
La valeur par défaut de DataContext pour un élément d’interface utilisateur est la valeur héritée de son parent. Vous pouvez remplacer cette valeur par défaut en définissant DataContext explicitement, ce qui est à son tour hérité par les enfants par défaut. La définition DataContext explicite sur un élément est utile lorsque vous souhaitez avoir plusieurs liaisons qui utilisent la même source.
Un objet de liaison a une Source propriété, qui correspond par défaut à DataContext de l’élément d’interface utilisateur sur lequel la liaison est déclarée. Vous pouvez remplacer cette valeur par défaut en définissant Source, RelativeSourceou ElementName explicitement sur la liaison (voir {Binding} pour plus d’informations).
À l’intérieur d’un DataTemplate, DataContext est automatiquement défini sur l’objet de données en cours de modèle. L’exemple suivant peut être utilisé comme contrôle ItemTemplate d’éléments lié à une collection de n’importe quel type qui a des propriétés de chaîne nommées Title et Description.
<DataTemplate x:Key="SimpleItemTemplate">
<StackPanel Orientation="Vertical" Height="50">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Description"/>
</StackPanel>
</DataTemplate>
Note
Par défaut, les modifications apportées à TextBox.Text sont envoyées à une source liée bidirectionnel lorsque textBox perd le focus. Pour que les modifications soient envoyées après chaque séquence de touches utilisateur, définissez-la UpdateSourceTriggerPropertyChanged sur la liaison dans le balisage. Vous pouvez également contrôler complètement le moment où les modifications sont envoyées à la source en définissant UpdateSourceTrigger sur Explicit. Vous gérez ensuite les événements sur la zone de texte (généralement TextBox.TextChanged), appelez GetBindingExpression sur la cible pour obtenir un objet BindingExpression , puis appelez BindingExpression.UpdateSource pour mettre à jour par programmation la source de données.
La propriété Path prend en charge diverses options de syntaxe pour la liaison à des propriétés imbriquées, des propriétés jointes et des indexeurs de chaînes et entiers. Pour plus d’informations, consultez la syntaxe property-path. La liaison à des indexeurs de chaîne vous donne l’effet de la liaison à des propriétés dynamiques sans avoir à implémenter ICustomPropertyProvider. La propriété ElementName est utile pour la liaison d’élément à élément. La propriété RelativeSource a plusieurs utilisations, dont l’une est une alternative plus puissante à la liaison de modèle à l’intérieur d’un ControlTemplate. Pour d’autres paramètres, consultez l’extension de balisage {Binding} et la classe Binding .
Que se passe-t-il si la source et la cible ne sont pas du même type ?
Si vous souhaitez contrôler la visibilité d’un élément d’interface utilisateur en fonction de la valeur d’une propriété booléenne, ou si vous souhaitez afficher un élément d’interface utilisateur avec une couleur qui est une fonction de la plage ou de la tendance d’une valeur numérique, ou si vous souhaitez afficher une valeur de date et/ou d’heure dans une propriété d’élément d’interface utilisateur qui attend une chaîne, vous devez ensuite convertir des valeurs d’un type en un autre. Il existe des cas où la solution appropriée consiste à exposer une autre propriété du type approprié à partir de votre classe source de liaison, et à conserver la logique de conversion encapsulée et testable là-bas. Mais cette solution n’est pas flexible ou évolutive lorsque vous avez de grands nombres ou de grandes combinaisons de propriétés source et cible. Dans ce cas, vous avez deux options :
- Si vous utilisez
{x:Bind}alors vous pouvez lier directement à une fonction pour effectuer cette conversion - Vous pouvez également spécifier un convertisseur de valeur qui est un objet conçu pour effectuer la conversion
Convertisseurs de valeurs
Voici un convertisseur de valeur, adapté à une liaison ponctuelle ou unidirectionnelle, qui convertit une valeur DateTime en valeur string contenant le mois. La classe implémente IValueConverter.
public class DateToStringConverter : IValueConverter
{
// Define the Convert method to convert a DateTime value to
// a month string.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// value is the data from the source object.
DateTime thisDate = (DateTime)value;
int monthNum = thisDate.Month;
string month;
switch (monthNum)
{
case 1:
month = "January";
break;
case 2:
month = "February";
break;
default:
month = "Month not found";
break;
}
// Return the value to pass to the target.
return month;
}
// ConvertBack is not implemented for a OneWay binding.
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Et voici comment vous utilisez ce convertisseur de valeur dans le balisage de votre objet de liaison.
<UserControl.Resources>
<local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0"
Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0"
Text="{Binding Month, Converter={StaticResource Converter1}}"/>
Le moteur de liaison appelle les méthodes Convert et ConvertBack si le paramètre Converter est défini pour la liaison. Lorsque les données sont transmises à partir de la source, le moteur de liaison appelle Convert et transmet les données retournées à la cible. Lorsque les données sont transmises à partir de la cible (pour une liaison bidirectionnelle), le moteur de liaison appelle ConvertBack et transmet les données retournées à la source.
Le convertisseur a également des paramètres facultatifs : ConverterLanguage, qui permet de spécifier la langue à utiliser dans la conversion et ConverterParameter, ce qui permet de transmettre un paramètre pour la logique de conversion. Pour obtenir un exemple qui utilise un paramètre de convertisseur, consultez IValueConverter.
Note
S’il existe une erreur dans la conversion, ne lèvez pas d’exception. Au lieu de cela, retourne DependencyProperty.UnsetValue, qui arrête le transfert de données.
Pour afficher une valeur par défaut à utiliser chaque fois que la source de liaison ne peut pas être résolue, définissez la FallbackValue propriété sur l’objet de liaison dans le balisage. Cela est utile pour gérer les erreurs de conversion et de mise en forme. Il est également utile de lier des propriétés sources qui n’existent peut-être pas sur tous les objets d’une collection liée de types hétérogènes.
Si vous liez un contrôle de texte à une valeur qui n’est pas une chaîne, le moteur de liaison de données convertit la valeur en chaîne. Si la valeur est un type de référence, le moteur de liaison de données récupère la valeur de chaîne en appelant ICustomPropertyProvider.GetStringRepresentation ou IStringable.ToString si disponible, et appelle sinon Object.ToString. Notez toutefois que le moteur de liaison ignore toute ToString implémentation qui masque l’implémentation de classe de base. Les implémentations de sous-classes doivent remplacer la méthode de classe ToString de base à la place. De même, dans les langages natifs, tous les objets managés semblent implémenter ICustomPropertyProvider et IStringable. Toutefois, tous les appels vers GetStringRepresentation et IStringable.ToString sont routés vers ou un Object.ToString remplacement de cette méthode, et jamais vers une nouvelle ToString implémentation qui masque l’implémentation de classe de base.
Note
Windows Community Toolkit fournit un BoolToVisibilityConverter. Le convertisseur mappe true à la Visible valeur d’énumération et falseCollapsed vous permet de lier une Visibility propriété à un booléen sans créer de convertisseur. Pour utiliser le convertisseur, votre projet doit ajouter le package NuGet CommunityToolkit.WinUI.Converters .
Liaison de fonction dans {x :Bind}
{x:Bind} permet à l’étape finale d’un chemin de liaison d’être une fonction. Utilisez cette fonctionnalité pour effectuer des conversions ou créer des liaisons qui dépendent de plusieurs propriétés. Pour plus d’informations, consultez Functions dans x :Bind.
Liaison d’élément à élément
Vous pouvez lier la propriété d’un élément XAML à la propriété d’un autre élément XAML. Voici un exemple de l’apparence de cette liaison de données dans le balisage.
<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />
Dictionnaires de ressources avec {x :Bind}
L’extension de balisage {x :Bind} dépend de la génération de code. Elle a donc besoin d’un fichier code-behind contenant un constructeur qui appelle InitializeComponent (pour initialiser le code généré). Pour réutiliser le dictionnaire de ressources, instanciez son type (donc appelé InitializeComponent ) au lieu de référencer son nom de fichier. Voici un exemple de ce qu’il faut faire si vous disposez d’un dictionnaire de ressources existant et que vous souhaitez l’utiliser {x:Bind} dans celui-ci.
<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
x:Class="ExampleNamespace.TemplatesResourceDictionary"
.....
xmlns:examplenamespace="using:ExampleNamespace">
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
<Grid>
<TextBlock Text="{x:Bind Name}"/>
</Grid>
</DataTemplate>
</ResourceDictionary>
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI.Xaml.Data;
namespace ExampleNamespace
{
public partial class TemplatesResourceDictionary
{
public TemplatesResourceDictionary()
{
InitializeComponent();
}
}
}
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
....
xmlns:examplenamespace="using:ExampleNamespace">
<Window.Resources>
<ResourceDictionary>
....
<ResourceDictionary.MergedDictionaries>
<examplenamespace:TemplatesResourceDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</Window>
Mélange de {x :Bind} et {Binding} dans un style réutilisable
L’exemple précédent a montré comment utiliser {x:Bind} dans DataTemplates. Vous pouvez également créer des styles réutilisables qui combinent les extensions de balisage {x:Bind} et {Binding}. Cette combinaison est utile lorsque vous souhaitez lier certaines propriétés aux valeurs connues au moment de la compilation en utilisant {x:Bind} et d'autres propriétés aux valeurs de DataContext au moment de l'exécution en utilisant {Binding}.
L’exemple suivant montre comment créer un style bouton réutilisable qui utilise les deux approches de liaison :
TemplatesResourceDictionary.xaml
<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
x:Class="ExampleNamespace.TemplatesResourceDictionary"
.....
xmlns:examplenamespace="using:ExampleNamespace">
<!-- DataTemplate using x:Bind -->
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
<Grid>
<TextBlock Text="{x:Bind Name}"/>
</Grid>
</DataTemplate>
<!-- Style that mixes x:Bind and Binding -->
<Style x:Key="CustomButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
<Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="RootBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<!-- x:Bind to a static property or page-level property -->
<Ellipse Width="8" Height="8"
Fill="{x:Bind DefaultIndicatorBrush}"
Margin="0,0,8,0"/>
<!-- Binding to DataContext -->
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}"/>
</StackPanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<!-- Binding to DataContext for hover color -->
<Setter Target="RootBorder.Background"
Value="{Binding ButtonHoverBrush}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<!-- x:Bind to a compile-time known resource -->
<Setter Target="RootBorder.Background"
Value="{x:Bind DefaultPressedBrush}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
TemplatesResourceDictionary.xaml.cs
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
namespace ExampleNamespace
{
public partial class TemplatesResourceDictionary
{
public TemplatesResourceDictionary()
{
InitializeComponent();
}
// Properties for x:Bind - these are compile-time bound
public SolidColorBrush DefaultIndicatorBrush { get; } =
new SolidColorBrush(Colors.Green);
public SolidColorBrush DefaultPressedBrush { get; } =
new SolidColorBrush(Colors.DarkGray);
}
}
Utilisation dans MainWindow.xaml avec un ViewModel qui fournit des valeurs d’exécution :
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
....
xmlns:examplenamespace="using:ExampleNamespace">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<examplenamespace:TemplatesResourceDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.DataContext>
<examplenamespace:ButtonThemeViewModel/>
</Grid.DataContext>
<StackPanel Margin="20">
<!-- These buttons use the mixed binding style -->
<Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
<Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
</StackPanel>
</Grid>
</Window>
ButtonThemeViewModel.cs (DataContext qui fournit des valeurs de liaison d’exécution) :
using System.ComponentModel;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;
namespace ExampleNamespace
{
public class ButtonThemeViewModel : INotifyPropertyChanged
{
private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);
public SolidColorBrush ButtonBackgroundBrush
{
get => _buttonBackgroundBrush;
set
{
_buttonBackgroundBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
}
}
public SolidColorBrush ButtonForegroundBrush
{
get => _buttonForegroundBrush;
set
{
_buttonForegroundBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
}
}
public SolidColorBrush ButtonHoverBrush
{
get => _buttonHoverBrush;
set
{
_buttonHoverBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Dans cet exemple :
-
{Binding}est utilisé pour les propriétés qui dépendent de DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush) -
{x:Bind}est utilisé pour les propriétés qui sont connues au moment de la compilation et appartiennent au ResourceDictionary lui-même (DefaultIndicatorBrush, DefaultPressedBrush) - Le style est réutilisable et vous pouvez l’appliquer à n’importe quel bouton
- Le thème du runtime est possible via DataContext tout en bénéficiant toujours des performances des
{x:Bind}éléments statiques
Liaison d’événements et ICommand
{x :Bind} prend en charge une fonctionnalité appelée liaison d’événements. Avec cette fonctionnalité, vous pouvez spécifier le gestionnaire d’un événement à l’aide d’une liaison. Cette fonctionnalité est une option supplémentaire pour la gestion des événements, en plus de la gestion des événements avec une méthode dans le fichier code-behind. Supposons que vous disposez d’un gestionnaire d’événements ListViewDoubleTapped dans votre MainWindow classe.
public sealed partial class MainWindow : Window
{
...
public void ListViewDoubleTapped()
{
// Handle double-tapped logic
}
}
Vous pouvez lier l’événement DoubleTapped d’un ListView à une méthode dans MainWindow comme suit.
<ListView DoubleTapped="{x:Bind ListViewDoubleTapped}" />
Vous ne pouvez pas utiliser de méthodes surchargées pour gérer un événement avec cette technique. En outre, si la méthode qui gère l’événement a des paramètres, toutes doivent être assignables à partir des types de tous les paramètres de l’événement, respectivement. Dans ce cas, ListViewDoubleTapped n’est pas surchargé et il n’a aucun paramètre (mais il serait toujours valide même s’il a pris deux object paramètres).
La technique de liaison d’événements est similaire à l’implémentation et à l’utilisation de commandes. Une commande est une propriété qui retourne un objet qui implémente l’interface ICommand .
{x :Bind} et {Binding} fonctionnent avec des commandes. Pour que vous n’ayez pas à implémenter le modèle de commande plusieurs fois, vous pouvez utiliser la DelegateCommand classe d’assistance que vous trouvez dans l’exemple UWP DezGame (dans le dossier « Common »).
Liaison à une collection de dossiers ou de fichiers
Vous pouvez utiliser les API dans l’espace de noms Windows.Storage pour récupérer des données de dossier et de fichier dans vos applications du Kit de développement logiciel (SDK) d’application Windows empaquetées. Toutefois, les méthodes GetFilesAsync, GetFoldersAsync et GetItemsAsync ne retournent pas de valeurs adaptées à la liaison avec les contrôles de liste. Au lieu de cela, vous devez établir une liaison aux valeurs de retour des méthodes GetVirtualizedFilesVector, GetVirtualizedFoldersVector et GetVirtualizedItemsVector de la classe FileInformationFactory . L’exemple de code suivant de l’exemple de code StorageDataSource et GetVirtualizedFilesVector UWP montre le modèle d’utilisation classique. N’oubliez pas de déclarer la fonctionnalité picturesLibrary dans le manifeste du package d’application et de confirmer qu’il existe des images dans votre dossier de bibliothèque d’images.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var library = Windows.Storage.KnownFolders.PicturesLibrary;
var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;
var fileQuery = library.CreateFileQueryWithOptions(queryOptions);
var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
fileQuery,
Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
190,
Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
false
);
var dataSource = fif.GetVirtualizedFilesVector();
this.PicturesListView.ItemsSource = dataSource;
}
Vous utilisez généralement cette approche pour créer une vue en lecture seule des informations de fichier et de dossier. Vous pouvez créer des liaisons bidirectionnelle aux propriétés de fichier et de dossier, par exemple pour permettre aux utilisateurs d’évaluer une chanson dans une vue musicale. Toutefois, les modifications ne sont pas conservées tant que vous n’appelez pas la méthode appropriée SavePropertiesAsync (par exemple , MusicProperties.SavePropertiesAsync). Vous devez valider les modifications lorsque l’élément perd le focus, car cette action déclenche une réinitialisation de sélection.
Notez que la liaison bidirectionnelle utilisant cette technique fonctionne uniquement avec des emplacements indexés, tels que Musique. Vous pouvez déterminer si un emplacement est indexé en appelant la méthode FolderInformation.GetIndexedStateAsync .
Notez également qu’un vecteur virtualisé peut retourner null pour certains éléments avant de remplir leur valeur. Par exemple, vous devez vérifier avant null d’utiliser la valeur SelectedItem d’un contrôle de liste lié à un vecteur virtualisé ou d’utiliser SelectedIndex à la place.
Liaison aux données regroupées par une clé
Si vous prenez une collection plate d’éléments (livres, par exemple, représentés par une BookSku classe) et que vous regroupez les éléments à l’aide d’une propriété commune en tant que clé (la BookSku.AuthorName propriété, par exemple), le résultat est appelé données groupées. Lorsque vous regroupez des données, il n’est plus une collection plate. Les données groupées sont une collection d’objets de groupe, où chaque objet de groupe a :
- une clé et
- collection d’éléments dont la propriété correspond à cette clé.
Pour reprendre l’exemple de livres, le résultat du regroupement des livres par nom d’auteur entraîne une collection de groupes de noms d’auteur où chaque groupe possède :
- une clé, qui est un nom d’auteur et
- collection des objets dont
BookSkulaAuthorNamepropriété correspond à la clé du groupe.
En général, pour afficher une collection, vous liez l’élément ItemsSource d’un contrôle d’éléments (tel que ListView ou GridView) directement à une propriété qui retourne une collection. Si c’est une collection plate d’éléments, vous n’avez pas besoin de faire quelque chose de spécial. Mais s’il s’agit d’une collection d’objets de groupe (comme c’est le cas lors de la liaison à des données groupées), vous avez besoin des services d’un objet intermédiaire appelé CollectionViewSource qui se trouve entre le contrôle d’éléments et la source de liaison. Vous liez la CollectionViewSource propriété qui retourne des données groupées, et vous liez le contrôle d’éléments au CollectionViewSource. Un ajout de valeur supplémentaire d’un CollectionViewSource est qu’il effectue le suivi de l’élément actuel, de sorte que vous pouvez conserver plusieurs contrôles d’éléments synchronisés en les liant tous au même CollectionViewSource. Vous pouvez également accéder à l’élément actuel par programmation via la propriété ICollectionView.CurrentItem de l’objet retourné par la propriété CollectionViewSource.View .
Pour activer la fonctionnalité de regroupement d’une CollectionViewSource, définissez IsSourceGrouped surtrue. Si vous devez également définir la propriété ItemsPath dépend exactement de la façon dont vous créez vos objets de groupe. Il existe deux façons de créer un objet de groupe : le modèle « is-a-group » et le modèle « has-a-group ». Dans le modèle « is-a-group », l’objet de groupe dérive d’un type de collection (par exemple), List<T>de sorte que l’objet de groupe est lui-même le groupe d’éléments. Avec ce modèle, vous n’avez pas besoin de définir ItemsPath. Dans le modèle « has-a-group », l’objet de groupe a une ou plusieurs propriétés d’un type de collection (par exemple), de sorte que List<T>le groupe « a un » groupe d’éléments sous la forme d’une propriété (ou plusieurs groupes d’éléments sous la forme de plusieurs propriétés). Avec ce modèle, vous devez définir ItemsPath le nom de la propriété qui contient le groupe d’éléments.
L’exemple suivant illustre le modèle « has-a-group ». La classe de fenêtre a une propriété nommée DataContext, qui retourne une instance de notre modèle de vue.
CollectionViewSource est lié à la Authors propriété du modèle d’affichage (Authorsest la collection d’objets de groupe) et spécifie également qu’il s’agit de la Author.BookSkus propriété qui contient les éléments groupés. Enfin, GridView est lié au CollectionViewSourcegroupe et a son style de groupe défini afin qu’il puisse afficher les éléments dans les groupes.
<Window.Resources>
<CollectionViewSource
x:Name="AuthorHasACollectionOfBookSku"
Source="{x:Bind ViewModel.Authors}"
IsSourceGrouped="true"
ItemsPath="BookSkus"/>
</Window.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
<GridView.GroupStyle>
<GroupStyle
HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
</GridView.GroupStyle>
</GridView>
Vous pouvez implémenter le modèle « is-a-group » de deux façons. L’une des façons consiste à créer votre propre classe de groupe. Dérivez la classe de List<T> (où T est le type des éléments). Par exemple : public class Author : List<BookSku>. La deuxième méthode consiste à utiliser une expression LINQ pour créer dynamiquement des objets de groupe (et une classe de groupe) à partir de valeurs de propriété des éléments BookSku . Cette approche, qui ne conserve qu’une liste plate d’éléments et les regroupe à la volée, est typique d’une application qui accède aux données à partir d’un service cloud. Vous bénéficiez de la flexibilité nécessaire pour regrouper des livres par auteur ou par genre (par exemple) sans avoir besoin de classes de groupe spéciales telles que Author et Genre.
L’exemple suivant illustre le modèle « is-a-group » à l’aide de LINQ. Cette fois, nous groupons les livres par genre, affichés avec le nom de genre dans les en-têtes de groupe. Ce regroupement est indiqué par le chemin de propriété « Key » en référence à la valeur de groupe Key.
using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;
public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
get
{
if (genres == null)
{
genres = from book in bookSkus
group book by book.genre into grp
orderby grp.Key
select grp;
}
return genres;
}
}
N’oubliez pas que lors de l’utilisation de {x :Bind} avec des modèles de données, vous devez indiquer le type auquel il est lié en définissant une x:DataType valeur. Si le type est générique, vous ne pouvez pas l’exprimer dans le balisage afin d’utiliser {Binding} à la place dans le modèle d’en-tête de style de groupe.
<Grid.Resources>
<CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
Source="{x:Bind Genres}"
IsSourceGrouped="true"/>
</Grid.Resources>
<GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
<GridView.ItemTemplate x:DataType="local:BookTemplate">
<DataTemplate>
<TextBlock Text="{x:Bind Title}"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
Un contrôle SemanticZoom est un excellent moyen pour vos utilisateurs d’afficher et de naviguer dans des données groupées. L’exemple d’application UWP Bookstore2 montre comment utiliser le SemanticZoomfichier . Dans cette application, vous pouvez afficher une liste de livres regroupés par auteur (vue avec zoom avant) ou vous pouvez effectuer un zoom arrière pour afficher une liste de raccourcis d’auteurs (vue zoom arrière). La liste de raccourcis offre une navigation beaucoup plus rapide que le défilement de la liste des livres. Les vues avec zoom avant et arrière sont en fait ListView ou GridView des contrôles liés au même CollectionViewSource.
Lorsque vous établissez une liaison à des données hiérarchiques( telles que des sous-catégories au sein des catégories), vous pouvez choisir d’afficher les niveaux hiérarchiques dans votre interface utilisateur avec une série de contrôles d’éléments. Une sélection dans un contrôle d’éléments détermine le contenu des contrôles d’éléments suivants. Vous pouvez conserver les listes synchronisées en liant chaque liste à sa propre CollectionViewSource et en liant les CollectionViewSource instances dans une chaîne. Cette configuration est appelée vue maître/détails (ou liste/détails). Pour plus d’informations, consultez Comment lier des données hiérarchiques et créer une vue maître/détails.
Diagnostic et débogage des problèmes de liaison de données
Votre balisage de liaison contient les noms des propriétés (et, pour C#, parfois des champs et des méthodes). Par conséquent, lorsque vous renommez une propriété, vous devez également modifier toute liaison qui le référence. Si vous oubliez de le faire, vous créez un bogue de liaison de données et votre application ne compile pas ou ne s’exécute pas correctement.
Les objets de liaison créés par {x :Bind} et {Binding} sont largement équivalents fonctionnellement. Mais {x:Bind} contient des informations de type pour la source de liaison et génère du code source au moment de la compilation. Avec {x:Bind}, vous obtenez le même type de détection de problème que vous obtenez avec le reste de votre code. Cette détection inclut la validation au moment de la compilation de vos expressions de liaison et le débogage en définissant des points d’arrêt dans le code source généré en tant que classe partielle pour votre page. Vous trouverez ces classes dans les fichiers de votre obj dossier, avec des noms tels que (pour C#). <view name>.g.cs Si vous rencontrez un problème avec une liaison, activez l’option Arrêter les exceptions non gérées dans le débogueur Microsoft Visual Studio. Le débogueur interrompt l’exécution à ce stade, et vous pouvez ensuite déboguer ce qui s’est passé. Le code généré par {x:Bind} suit le même modèle pour chaque partie du graphique des nœuds sources de liaison, et vous pouvez utiliser les informations dans la fenêtre Pile des appels pour vous aider à déterminer la séquence d’appels qui a conduit au problème.
{Binding} ne possède pas d’informations de type pour la source de liaison. Toutefois, lorsque vous exécutez votre application avec le débogueur attaché, toutes les erreurs de liaison apparaissent dans les fenêtres Sortie et Échecs de liaison XAML dans Visual Studio. Pour plus d’informations sur le débogage des erreurs de liaison dans Visual Studio, consultez diagnostics de liaison de données XAML.
Création de liaisons dans le code
Note
Cette section s’applique uniquement à {Binding}, car vous ne pouvez pas créer de liaisons {x :Bind} dans le code. Toutefois, vous pouvez obtenir certains des mêmes avantages avec {x:Bind}DependencyObject.RegisterPropertyChangedCallback, ce qui vous permet d’inscrire des notifications de modification sur n’importe quelle propriété de dépendance.
Vous pouvez également connecter des éléments d’interface utilisateur à des données à l’aide de code procédural au lieu de XAML. Pour ce faire, créez un objet Binding , définissez les propriétés appropriées, puis appelez FrameworkElement.SetBinding ou BindingOperations.SetBinding. La création de liaisons par programmation est utile lorsque vous souhaitez choisir les valeurs de propriété de liaison au moment de l’exécution ou partager une seule liaison entre plusieurs contrôles. Toutefois, vous ne pouvez pas modifier les valeurs de propriété de liaison après l’appel SetBinding.
L’exemple suivant montre comment implémenter une liaison dans le code.
<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class
// that implements INotifyPropertyChanged.
var textcolor = new MyColors();
// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);
// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;
// Create the binding and associate it with the text box.
var binding = new Binding { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);
Comparaison des fonctionnalités {x :Bind} et {Binding}
| Caractéristique | {x :Bind} et {Binding} | Remarques |
|---|---|---|
| Chemin d’accès est la propriété par défaut | {x:Bind a.b.c}- {Binding a.b.c} |
|
| Path, propriété | {x:Bind Path=a.b.c}- {Binding Path=a.b.c} |
Dans x:Bind, Path est rooté sur la fenêtre par défaut, et non sur DataContext. |
| Indexer | {x:Bind Groups[2].Title}- {Binding Groups[2].Title} |
Lie à l’élément spécifié dans la collection. Seuls les index basés sur des entiers sont pris en charge. |
| Propriétés jointes | {x:Bind Button22.(Grid.Row)}- {Binding Button22.(Grid.Row)} |
Les propriétés jointes sont spécifiées à l’aide de parenthèses. Si la propriété n’est pas déclarée dans un espace de noms XAML, préfixez-la avec un espace de noms XML, qui doit être mappé à un espace de noms de code à la tête du document. |
| Casting | {x:Bind groups[0].(data:SampleDataGroup.Title)}- Non nécessaire pour {Binding}. |
Les casts sont spécifiés à l’aide de parenthèses. Si la propriété n’est pas déclarée dans un espace de noms XAML, préfixez-la avec un espace de noms XML, qui doit être mappé à un espace de noms de code à la tête du document. |
| Convertisseur | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}- {Binding IsShown, Converter={StaticResource BoolToVisibility}} |
Déclarez des convertisseurs à la racine de la fenêtre, du contrôle, de ResourceDictionary ou dans App.xaml. |
| ParamètreConvertisseur, LangueConvertisseur | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}- {Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr} |
Déclarez des convertisseurs à la racine de la fenêtre, du contrôle, de ResourceDictionary ou dans App.xaml. |
| TargetNullValue | {x:Bind Name, TargetNullValue=0}- {Binding Name, TargetNullValue=0} |
Utilisé lorsque la feuille de l’expression de liaison a la valeur Null. Utilisez des guillemets simples pour une valeur de chaîne. |
| FallbackValue | {x:Bind Name, FallbackValue='empty'}- {Binding Name, FallbackValue='empty'} |
Utilisé quand une partie du chemin d’accès de la liaison (à l’exception de la feuille) a la valeur Null. |
| ElementName | {x:Bind slider1.Value}- {Binding Value, ElementName=slider1} |
Avec {x:Bind}, vous établissez une liaison avec un champ ; Path est par défaut ancré dans la fenêtre, vous pouvez donc accéder à n’importe quel élément nommé via son champ. |
| RelativeSource : Self | <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />- <Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... /> |
Avec {x:Bind}, nommez l’élément et utilisez son nom dans Path. |
| RelativeSource : TemplatedParent | Non nécessaire pour {x:Bind}- {Binding <path>, RelativeSource={RelativeSource TemplatedParent}} |
Avec {x:Bind}, TargetType on ControlTemplate indique la liaison au parent du modèle. Pour {Binding}, la liaison de modèle standard peut être utilisée dans les modèles de contrôle pour la plupart des utilisations. Toutefois, utilisez TemplatedParent l’emplacement où vous devez utiliser un convertisseur ou une liaison bidirectionnelle. |
| Origine | Non nécessaire pour {x:Bind}- <ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/> |
Pour {x:Bind} vous pouvez utiliser directement l’élément nommé, utiliser une propriété ou un chemin d’accès statique. |
| Mode | {x:Bind Name, Mode=OneWay}- {Binding Name, Mode=TwoWay} |
Mode peut être OneTime, OneWayou TwoWay.
{x:Bind}
OneTimevaleur par défaut : valeur {Binding} par défaut OneWay: . |
| UpdateSourceTrigger | {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}- {Binding UpdateSourceTrigger=PropertyChanged} |
UpdateSourceTrigger peut être Default, LostFocusou PropertyChanged.
{x:Bind} ne prend pas en charge UpdateSourceTrigger=Explicit.
{x:Bind} utilise PropertyChanged le comportement pour tous les cas sauf TextBox.Text, où il utilise LostFocus le comportement. |
Voir aussi
Windows developer