RelativeSources in WPF bindings

The RelativeSource is a markup extension that is used in particular binding cases when we try to bind a property of a given object to another property of the object itself, when we try to bind a property of a object to another one of its relative parents, when binding a dependency property value to a piece of XAML in case of custom control development and finally in case of using a differential of a series of a bound data. All of those situations are expressed as relative source modes. I will expose all of those cases one by one.

1. Mode Self:

Imagine this case, a rectangle that we want that its height is always equal to its width, a square let’s say. We can do this using the element name

<Rectangle Fill=”Red” Name=”rectangle”
Height=”100″ Stroke=”Black”
Canvas.Top=”100″ Canvas.Left=”100″
Width=”{Binding ElementName=rectangle,
Path=Height}”/>

But in this above case we are obliged to indicate the name of the binding object, namely the rectangle. We can reach the same purpose differently using the RelativeSource

<Rectangle Fill=”Red” Height=”100″
Stroke=”Black”
Width=”{Binding RelativeSource={RelativeSource Self},
Path=Height}”/>

For that case we are not obliged to mention the name of the binding object and the Width will be always equal to the Height whenever the height is changed.

If you want to parameter the Width to be the half of the height then you can do this by adding a converter to the Binding markup extension.
Let’s imagine another case now:

<TextBlock Width=”{Binding RelativeSource={RelativeSource Self},
Path=Parent.ActualWidth}”/>

The above case is used to tie a given property of a given element to one of its direct parent ones as this element holds a property that is called Parent. This leads us to another relative source mode which is the FindAncestor one.

2. Mode FindAncestor

In this case, a property of a given element will be tied to one of its parents, Of Corse. The main difference with the above case is the fact that, it’s up to you to determine the ancestor type and the ancestor rank in the hierarchy to tie the property. By the way try to play with this piece of XAML

<Canvas Name=”Parent0″>
<Border Name=”Parent1″
Width=”{Binding RelativeSource={RelativeSource Self},
Path=Parent.ActualWidth}”
Height=”{Binding RelativeSource={RelativeSource Self},
Path=Parent.ActualHeight}”>
<Canvas Name=”Parent2″>
<Border Name=”Parent3″
Width=”{Binding RelativeSource={RelativeSource Self},
Path=Parent.ActualWidth}”
Height=”{Binding RelativeSource={RelativeSource Self},
Path=Parent.ActualHeight}”>
<Canvas Name=”Parent4″>
<TextBlock FontSize=”16″
Margin=”5″ Text=”Display the name of the ancestor”/>
<TextBlock FontSize=”16″
Margin=”50″
Text=”{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Border},
AncestorLevel=2},Path=Name}”
Width=”200″/>
</Canvas>
</Border>
</Canvas>
</Border>
</Canvas>

The above situation is of two TextBlock elements those are embedded within a series of borders and canvas elements those represent their hierarchical parents. The second TextBlock will display the name of the given parent at the relative source level.

So try to change AncestorLevel=2 to AncestorLevel=1 and see what happens. Then try to change the type of the ancestor from AncestorType=Border to AncestorType=Canvas and see what’s happens.

The displayed text will change according to the Ancestor type and level. Then what’s happen if the ancestor level is not suitable to the ancestor type? This is a good question, I know that you’re about to ask it. The response is no exceptions will be thrown and nothings will be displayed at the TextBlock level.

3. TemplatedParent

This mode enables tie a given ControlTemplate property to a property of the control that the ControlTemplate is applied to. To well understand the issue here is an example bellow

<Window.Resources>
<ControlTemplate x:Key=”template”>
<Canvas>
<Canvas.RenderTransform>
<RotateTransform Angle=”20″/>
</Canvas.RenderTransform>
<Ellipse Height=”100″ Width=”150″
Fill=”{Binding
RelativeSource={RelativeSource TemplatedParent},
Path=Background}”>

</Ellipse>
<ContentPresenter Margin=”35″
Content=”{Binding RelativeSource={RelativeSource
TemplatedParent},Path=Content}”/>
</Canvas>
</ControlTemplate>
</Window.Resources>
<Canvas Name=”Parent0″>
<Button   Margin=”50″
Template=”{StaticResource template}” Height=”0″
Canvas.Left=”0″ Canvas.Top=”0″ Width=”0″>
<TextBlock FontSize=”22″>Click me</TextBlock>
</Button>
</Canvas>

If I want to apply the properties of a given control to its control template then I can use the TemplatedParent mode. There is also a similar one to this markup extension which is the TemplateBinding which is a kind of short hand of the first one, but the TemplateBinding is evaluated at compile time at the contrast of the TemplatedParent which is evaluated just after the first run time. As you can remark in the bellow figure, the background and the content are applied from within the button to the control template.

4. PreviousData

This is the most ambiguous and the less used mode of the RelativeSource, I mean the PreviousData one. The PreviousData is used for particular cases. Its purpose is to tie the given property to another property with a particular assignment; I mean it assigns the previous value of the property to the bound one. In other word, if you have a TextBox that has a text property and another control that has a value property that holds data. Say that value is actually 5 and it was 3 just before. The 3 is assigned to the text property of the TextBox and not 5. This leads to the idea that this kind of RelativeSource is frequently used with the items controls.

So

If you want to bind to another property on the object:

{BindingPath=PathToProperty,RelativeSource={RelativeSourceSelf}}

If you want to get a property on an ancestor:

{BindingPath=PathToProperty,RelativeSource={RelativeSourceAncestorType={x:Type typeOfAncestor}}}

If you want to get a property on the templated parent (so you can do 2 way bindings in a ControlTemplate)

{BindingPath=PathToProperty,RelativeSource={RelativeSourceTemplatedParent}}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s