Binding: quelques exemples concrets (XAML)
Par Eric. WPF Binding | Lien permanent.
Avec et grâce aux propriétés de dépendance, le binding est l'un des principaux attraits de WPF. Voici quelques cas d'utilisation, en fonction du lien de parenté entre les deux propriétés liées.
La méthode dépend surtout de la source de la liaison.
Bien qu'il soit souvent plus simple et efficace d'établir la liaison à partir d'une propriété de dépendance, ce n'est pas obligatoire. La liaison Binding supporte également l'interface INotifyPropertyChanged. La cible de la liaison est, quant à elle, nécessairement une propriété de dépendance.
A défaut de précision, le Binding se base sur la la propriété de dépendance de l'objet cible DataContext (héritée ou explicitement définie). Par ailleurs, la source peut être précisée à partir de l'une de celles-ci :
- Source
- RelativeSource
- ElementName
Ces trois sources sont exclusives: seule l'une d'elle doit être définie.
Cas le plus simple: liaison sur le DataContext de l'objet
Tout objet dérivant de FrameworkElement possède une propriété DataContext. Celle-ci peut contenir une référence vers tout type d'objet.
L'exemple qui suit est valide si le contrôle TextBlock référence un objet qui définit une propriété Test dans sa propriété DataContext:
<TextBlock Text="{Binding Test}"/>
Equivalent à :
<TextBlock Text="{Binding Path=Test}"/>
Liaison sur une source relative: RelativeSource
Comme l'indique MSDN, on utilise généralement RelativeSource pour établir une liaison sur l'objet lui-même ou dans un Style ou Template.
L'attribut par défaut de RelativeSource est RelativeSource.Mode. La valeur peut être :
Mode=SelfMode=FindAncestorMode=PreviousDataMode=TemplatedParent
Notez qu'en Silverlight 3, les seules valeurs possibles sont
SelfetTemplatedParent(cf. MSDN). Une alternative est de définir la liaison côté code, via la méthodeSetBinding()duDependencyObject. Ainsi, la liaison est possible à partir de/vers tout élément accessible côté code.
Sur soi-même: Self
Dans l'exemple suivant, le contrôle TextBlock établit la liaison sur une de ses propres propriétés:
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth}"/>
Sur un objet parent: AncestorType et/ou AncestorLevel
Si l'un de ces deux attributs est défini, la propriété Mode est implicitement redéfinie à FindAncestor.
L'exemple suivant est valide si l'objet MyClass dérivant de UserControl définit une propriété MyImage de type ImageSource:
<UserControl x:Class="Space.MyClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=MyImage}"/>
</Grid>
Dans ce cas précis, équivalent à :
<UserControl x:Class="Space.MyClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Space">
<Grid>
<Image Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyClass}}, Path=MyImage}"/>
</Grid>
Cette dernière forme est à privilégier.
Par défaut, AncestorLevel=1, ce qui équivaut à rechercher l'ancêtre le plus proche de la cible de la liaison. Redéfinir cette propriété permet de remonter plus haut dans les ancêtres.
Sur l'objet sur lequel est appliqué le template: TemplatedParent
Dans un template, l'exemple suivant définit le DataContext d'un panel Grid à partir de la propriété ItemSource de l'objet sur lequel est appliqué ce ControlTemplate:
<ControlTemplate x:Key="MyTemplate"
TargetType="{x:Type ComboBox}">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}">
[...]
</Grid>
</ControlTemplate>
Sur un autre élément de l'application: ElementName
Cet exemple est directement tiré de MSDN:
<DockPanel>
<TextBlock>Choose a Color:</TextBlock>
<ComboBox Name="myComboBox" SelectedIndex="0">
<ComboBoxItem>Green</ComboBoxItem>
<ComboBoxItem>Blue</ComboBoxItem>
<ComboBoxItem>Red</ComboBoxItem>
</ComboBox>
<Canvas>
<Canvas.Background>
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
</Canvas.Background>
</Canvas>
</DockPanel>
Si l'élément source a été déclaré côté code, il doit avoir été préalablement enregistré dans la portée locale.
L'exemple partiel suivant rend accessible le contrôle TextBox
public partial class Demo : Page
{
private TextBox myText = new TextBox();
public Demo()
{
NameScope.SetNameScope(this, new NameScope());
this.RegisterName("myText", myText);
}
Un exemple complet et concret est présenté sur MSDN: Comment : créer une réflexion
Sur une propriété attachée
La liaison d'une propriété de dépendance sur une propriété attachée n'a pas réellement de particuliarité. Il faut simplement faire attention à la notation lorsqu'un espace de nom préfixe le chemin de la propriété.
L'exemple suivant est basé sur l'article de Samuel Jack. Ce dernier explique comment créer une liaison sur la propriété Password d'un contrôle PasswordBox. En effet, PasswordBox.Password n'est pas une propriété de dépendance. Le code ci-dessous utilise la classe statique proprosée par Samuel Jack, en se liant notamment à l'une de ses propriétés attachées :
<PasswordBox Name="txtPin"
local:PasswordBoxHelper.BindPassword="true"
local:PasswordBoxHelper.BoundPassword="{Binding RelativeSource={RelativeSource Self}, Path=Password, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=(local:PasswordBoxHelper.BoundPassword), ElementName=txtPin, Mode=OneWay}"/>