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=Self
  • Mode=FindAncestor
  • Mode=PreviousData
  • Mode=TemplatedParent

Notez qu'en Silverlight 3, les seules valeurs possibles sont Self et TemplatedParent (cf. MSDN). Une alternative est de définir la liaison côté code, via la méthode SetBinding() du DependencyObject. 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}"/>

Voir aussi:

Dependency Properties et Binding