March 25th, 2020

Increase Binding Possibilities with RelativeSource

Javier Suárez
Senior Software Engineer

The BindingContext is one of the most important parts of the Xamarin.Forms data binding system, especially in MVVM applications. Being built into the Binding type as the common source for bindings in a specific scope reduces plumbing code needed and makes XAML more concise. Unfortunately, for any given View there is only one BindingContext available to bind against. Most of the time this isn’t a problem, but complex data hierarchies often lead to situations where an element needs to bind to the BindingContext of some parent element in addition to its own local BindingContext. For example, you are working with a collection of items using CollectionView. In the DataTemplate of each element you need a Button associated with a Command. However, by default, the BindingContext in the template is an item from the collection. How do we access a Command in the BindingContext of the CollectionView?.

RelativeSource

The RelativeSource is a markup extension that is used when we want to bind a property of a given element to another property of the element itself, when we want to bind a property of a element to another one of its relative parents, and when we want to bind a bindable property value to a piece of XAML in custom control development. All of those situations are expressed as relative source modes. RelativeSource has the following modes:
  1. Self
  2. Find Ancestor
  3. Templated Parent 

1. Self

Self indicates the element on which the binding is being set, allowing you to bind one property of that element to another property on the same element. For example, we want to draw a square using a BoxView. We can do this using the element name:
<BoxView 
    x:Name="myBoxView"
    Color="Red"  
    HeightRequest="100"
    WidthRequest="{Binding Source={x:Reference myBoxView}, Path=HeightRequest}}" />
Alternatively, we can achieve the same result using the RelativeSource:
<BoxView 
    Color="Red"
    HeightRequest="100"
    Width="{Binding Source={RelativeSource Self}, Path=HeightRequest}"/>

Using FindAncestor relative source

2. Find Ancestor

The FindAncestor relative binding modes are used to bind to parent elements in the visual tree. 
<CollectionView
    ItemsSource="{Binding Drinks}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid>
            ...  
            <Button
                Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:RelativeSourceViewModel}}, Path=BuyCommand}"
                CommandParameter="{Binding Source={RelativeSource Self}, Path=BindingContext}"
                ... />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

In this example, the BindingContext of the page is set to the RelativeSourceViewModel property of itself. The CollectionView binds to the Drinks property of the viewmodel. The DataTemplate, which defines the appearance of each item in the CollectionView, contains a Button. The button’s Command property is bound to the BuyCommand in its parent’s viewmodel. 

The AncestorType property should be set to the type of the element to use as the source.

Using FindAncestor relative source

3. Templated Parent

This mode enables you to tie a given ControlTemplate property to a property of the control that the ControlTemplate is applied to.  
To better understand this mode, let’s see an example:
<ControlTemplate x:Key="DrinkCardViewControlTemplate">
    <Grid>
        <Frame
            BindingContext="{Binding Source={RelativeSource TemplatedParent}}">
            <StackLayout>
                <Label 
                    Text="{Binding DrinkTitle}"
                    ... />
                ...
            </Grid>
        </Frame>
    </Grid>
</ControlTemplate>

In this example, the Frame, which is the root element of the ControlTemplate, has its BindingContext set to the runtime object instance to which the template is applied. Therefore, the Frame and its children resolve their binding expressions against the properties of each custom control object.

<controls:DrinkCardView
     DrinkTitle="BRAZILIAN COFFEE"
     DrinkDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
     DrinkColor="Maroon"
     DrinkImageSource="coffee.png"
     ControlTemplate="{StaticResource DrinkCardViewControlTemplate}" />

Using TemplatedParent relative source

Learn More

Hopefully this blog was helpful and showed you how easy it is to use RelativeSource. You can find the sample we have seen in this article and read more about RelativeSource in our amazing documentation.

Author

Javier Suárez
Senior Software Engineer

Javier Suárez is a software engineer at Microsoft for the Xamarin.Forms team. Javier involves himself in speaking, providing (video) training sessions and writing blogs and articles and contributing to open-source projects in his spare time.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Dmytro Bondarenko

    P1, example 2:
    Width=”{Binding RelativeSource={RelativeSource Self}, Path=HeightRequest}”/>
    Maybe Source is the correct word?

    • Javier SuárezMicrosoft employee Author

      You’re right Dmytro. It’s already changed.

  • Reed

    Great article, I’ve been looking forward to this feature.
    From which Xamarin.Forms version is this feature supported?

  • Dimitris Tavlikos

    Excellent, this is very useful. Now we don’t have to be creating new ViewModels for specific controls in a page.