wpf
Introduction à la liaison de données WPF
Recherche…
Syntaxe
- {Binding PropertyName} est équivalent à {Binding Path = PropertyName}
- {Chemin de liaison = SomeProperty.SomeOtherProperty.YetAnotherProperty}
- {Chemin de liaison = SomeListProperty [1]}
Paramètres
Paramètre | Détails |
---|---|
Chemin | Spécifie le chemin d'accès à lier. Si non spécifié, se lie au DataContext lui-même. |
UpdateSourceTrigger | Spécifie à quel moment la source de liaison a sa valeur mise à jour. Par défaut, LostFocus . La valeur la plus utilisée est PropertyChanged . |
Mode | Généralement OneWay ou TwoWay . S'il n'est pas spécifié par la liaison, sa valeur par défaut est OneWay sauf si la cible de liaison le demande comme TwoWay . Une erreur se produit lorsque TwoWay est utilisé pour se lier à une propriété en lecture seule, par exemple, OneWay doit être défini explicitement lors de la liaison d'une propriété de chaîne en lecture seule à TextBox.Text . |
La source | Permet d'utiliser un StaticResource comme source de liaison au lieu du DataContext actuel. |
RelativeSource | Permet d'utiliser un autre élément XAML comme source de liaison au lieu du DataContext actuel. |
ElementName | Permet d'utiliser un élément XAML nommé comme source de liaison au lieu du DataContext actuel. |
Valeur de repli | Si la liaison échoue, cette valeur est fournie à la cible de liaison. |
TargetNullValue | Si la valeur source de liaison est null , cette valeur est fournie à la cible de liaison. |
Convertisseur | Spécifie le convertisseur StaticResource utilisé pour convertir la valeur de la liaison, par exemple, convertir un booléen en un élément enum de Visibility . |
ConvertisseurParamètre | Spécifie un paramètre facultatif à fournir au convertisseur. Cette valeur doit être statique et ne peut pas être liée. |
StringFormat | Spécifie une chaîne de format à utiliser lors de l'affichage de la valeur liée. |
Retard | (WPF 4.5+) Spécifie un délai en milliseconds pendant BindingSource la liaison met à jour le BindingSource dans ViewModel . Cela doit être utilisé avec Mode=TwoWay et UpdateSourceTrigger=PropertyChanged pour prendre effet. |
Remarques
UpdateSourceTrigger
Par défaut, WPF met à jour la source de liaison lorsque le contrôle perd le focus. Cependant, s'il n'y a qu'un seul contrôle capable d'obtenir le focus - quelque chose qui est courant dans les exemples - vous devrez spécifier UpdateSourceTrigger=PropertyChanged
pour que les mises à jour fonctionnent.
Vous voudrez peut-être utiliser PropertyChanged
comme déclencheur sur de nombreuses liaisons bidirectionnelles, à moins que la mise à jour de la source de liaison sur chaque frappe ne soit coûteuse ou que la validation des données en direct soit indésirable.
L'utilisation de LostFocus
a un effet secondaire regrettable: appuyer sur Entrée pour soumettre un formulaire à l'aide d'un bouton marqué IsDefault
ne met pas à jour la propriété de sauvegarde de votre liaison, annulant ainsi vos modifications. Heureusement, certaines solutions existent .
Notez également que, contrairement à UWP, WPF (4.5+) possède également la propriété Delay
dans les liaisons, ce qui peut être suffisant pour certaines liaisons avec des paramètres d'intelligence mineure locale ou simple, comme certaines validations TextBox
.
Convertir un booléen en valeur de visibilité
Cet exemple masque la zone rouge (bordure) si la case à cocher n'est pas cochée en utilisant un IValueConverter
.
Remarque: Le BooleanToVisibilityConverter
utilisé dans l'exemple ci-dessous est un convertisseur de valeur intégré situé dans l'espace de noms System.Windows.Controls.
XAML:
<Window x:Class="StackOverflowDataBindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources>
<StackPanel>
<CheckBox x:Name="MyCheckBox"
IsChecked="True" />
<Border Background="Red" Width="20" Height="20"
Visibility="{Binding Path=IsChecked,ElementName=MyCheckBox, Converter={StaticResource VisibleIfTrueConverter}}" />
</StackPanel>
</Window>
Définir le contexte de données
Pour pouvoir utiliser des liaisons dans WPF, vous devez définir un DataContext . Le DataContext indique aux liaisons où récupérer leurs données par défaut.
<Window x:Class="StackOverflowDataBindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOverflowDataBindingExample"
xmlns:vm="clr-namespace:StackOverflowDataBindingExample.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:HelloWorldViewModel />
</Window.DataContext>
...
</Window>
Vous pouvez également définir le DataContext via code-behind, mais il convient de noter que XAML IntelliSense est un peu difficile: un DataContext fortement typé doit être défini dans XAML pour que IntelliSense suggère des propriétés disponibles pour la liaison.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new HelloWorldViewModel();
}
}
Bien qu'il existe des frameworks pour vous aider à définir votre DataContext de manière plus flexible (par exemple, MVVM Light a un localisateur de vue qui utilise l' inversion du contrôle ), nous utilisons la méthode rapide et sale pour les besoins de ce tutoriel.
Vous pouvez définir un DataContext pour pratiquement tous les éléments visuels de WPF. Le DataContext est généralement hérité des ancêtres de l’arborescence visuelle, sauf s’il a été explicitement remplacé, par exemple au sein d’un ContentPresenter.
Implémenter INotifyPropertyChanged
INotifyPropertyChanged
est une interface utilisée par les sources de liaison (c.-à-d. Le DataContext) pour permettre à l'interface utilisateur ou à d'autres composants de savoir qu'une propriété a été modifiée. WPF met automatiquement à jour l'interface utilisateur lorsqu'elle détecte l'événement PropertyChanged
déclenché. Il est souhaitable que cette interface soit implémentée sur une classe de base dont tous vos modèles de vues peuvent hériter.
En C # 6, c'est tout ce dont vous avez besoin:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Cela vous permet d'appeler NotifyPropertyChanged
de deux manières différentes:
-
NotifyPropertyChanged()
, quiNotifyPropertyChanged()
l'événement pour le setter qui l'invoque, grâce à l'attribut CallerMemberName . -
NotifyPropertyChanged(nameof(SomeOtherProperty))
, qui déclenchera l'événement pour SomeOtherProperty.
Pour .NET 4.5 et versions ultérieures utilisant C # 5.0, ceci peut être utilisé à la place:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Dans les versions de .NET antérieures à la version 4.5, vous devez définir des noms de propriété sous forme de constantes de chaîne ou une solution utilisant des expressions .
Remarque: Il est possible de lier une propriété d'un "objet C # ancien" (POCO) qui INotifyPropertyChanged
pas INotifyPropertyChanged
et observez que les liaisons fonctionnent mieux que prévu. Ceci est une fonctionnalité cachée dans .NET et devrait probablement être évitée. Surtout que cela entraînera des fuites de mémoire lorsque le Mode
de liaison n'est pas OneTime
(voir ici ).
Pourquoi la liaison est-elle mise à jour sans implémenter INotifyPropertyChanged?
Lier à la propriété d'un autre élément nommé
Vous pouvez associer une propriété à un élément nommé, mais l'élément nommé doit avoir une portée.
<StackPanel>
<CheckBox x:Name="MyCheckBox" IsChecked="True" />
<TextBlock Text="{Binding IsChecked, ElementName=MyCheckBox}" />
</StackPanel>
Lier à la propriété d'un ancêtre
Vous pouvez créer une liaison avec une propriété d'un ancêtre dans l'arborescence visuelle à l'aide d'une liaison RelativeSource
. Le contrôle le plus proche dans l'arborescence visuelle qui a le même type ou est dérivé du type que vous spécifiez sera utilisé comme source de la liaison:
<Grid Background="Blue">
<Grid Background="Gray" Margin="10">
<Border Background="Red" Margin="20">
<StackPanel Background="White" Margin="20">
<Button Margin="10" Content="Button1" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}" />
<Button Margin="10" Content="Button2" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}" />
</StackPanel>
</Border>
</Grid>
</Grid>
Dans cet exemple, Button1 a un arrière-plan gris car l'ancêtre de la Grid
le plus proche a un arrière-plan gris. Button2 a un arrière-plan blanc car l'ancêtre le plus proche dérivé de FrameworkElement
est le StackPanel
blanc.
Relier plusieurs valeurs avec un MultiBinding
MultiBinding permet de lier plusieurs valeurs à la même propriété. Dans l'exemple suivant, plusieurs valeurs sont liées à la propriété Text d'une zone de texte et mises en forme à l'aide de la propriété StringFormat.
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="User.Forename"/>
<Binding Path="User.Surname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
En dehors de StringFormat
, un IMultiValueConverter
peut également être utilisé pour convertir les valeurs des liaisons en une seule valeur pour la cible du MultiBinding.
Toutefois, les MultiBindings ne peuvent pas être imbriqués.