Relative bindings
.NET Multi-platform App UI (.NET MAUI) relative bindings provide the ability to set the binding source relative to the position of the binding target. They are created with the RelativeSource
markup extension, and set as the Source
property of a binding expression.
The RelativeSource
markup extension is supported by the RelativeSourceExtension
class, which defines the following properties:
Mode
, of typeRelativeBindingSourceMode
, describes the location of the binding source relative to the position of the binding target.AncestorLevel
, of typeint
, an optional ancestor level to look for, when theMode
property isFindAncestor
. AnAncestorLevel
ofn
skipsn-1
instances of theAncestorType
.AncestorType
, of typeType
, the type of ancestor to look for, when theMode
property isFindAncestor
.
Note
The XAML parser allows the RelativeSourceExtension
class to be abbreviated as RelativeSource
.
The Mode
property should be set to one of the RelativeBindingSourceMode
enumeration members:
TemplatedParent
indicates the element to which the template, in which the bound element exists, is applied. For more information, see Bind to a templated parent.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 more information, see Bind to self.FindAncestor
indicates the ancestor in the visual tree of the bound element. This mode should be used to bind to an ancestor control represented by theAncestorType
property. For more information, see Bind to an ancestor.FindAncestorBindingContext
indicates theBindingContext
of the ancestor in the visual tree of the bound element. This mode should be used to bind to theBindingContext
of an ancestor represented by theAncestorType
property. For more information, see Bind to an ancestor.
The Mode
property is the content property of the RelativeSourceExtension
class. Therefore, for XAML markup expressions expressed with curly braces, you can eliminate the Mode=
part of the expression.
For more information about .NET MAUI markup extensions, see Consume XAML markup extensions.
Bind to self
The Self
relative binding mode is used bind a property of an element to another property on the same element:
<BoxView Color="Red"
WidthRequest="200"
HeightRequest="{Binding Source={RelativeSource Self}, Path=WidthRequest}"
HorizontalOptions="Center" />
In this example, the BoxView sets its WidthRequest property to a fixed size, and the HeightRequest property binds to the WidthRequest property. Therefore, both properties are equal and so a square is drawn:
Important
When binding a property of an element to another property on the same element, the properties must be the same type. Alternatively, you can specify a converter on the binding to convert the value.
A common use of this binding mode is set an object's BindingContext
to a property on itself. The following code shows an example of this:
<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
...
</ListView>
</StackLayout>
</ContentPage>
In this example, the BindingContext
of the page is set to the DefaultViewModel
property of itself. This property is defined in the code-behind file for the page, and provides a viewmodel instance. The ListView binds to the Employees
property of the viewmodel.
Bind to an ancestor
The FindAncestor
and FindAncestorBindingContext
relative binding modes are used to bind to parent elements, of a certain type, in the visual tree. The FindAncestor
mode is used to bind to a parent element, which derives from the Element type. The FindAncestorBindingContext
mode is used to bind to the BindingContext
of a parent element.
Warning
The AncestorType
property must be set to a Type
when using the FindAncestor
and FindAncestorBindingContext
relative binding modes, otherwise a XamlParseException
is thrown.
If the Mode
property isn't explicitly set, setting the AncestorType
property to a type that derives from Element will implicitly set the Mode
property to FindAncestor
. Similarly, setting the AncestorType
property to a type that does not derive from Element will implicitly set the Mode
property to FindAncestorBindingContext
.
Note
Relative bindings that use the FindAncestorBindingContext
mode will be reapplied when the BindingContext
of any ancestors change.
The following XAML shows an example where the Mode
property will be implicitly set to FindAncestorBindingContext
:
<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Fullname}"
VerticalOptions="Center" />
<Button Text="Delete"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeleteEmployeeCommand}"
CommandParameter="{Binding}"
HorizontalOptions="End" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
In this example, the BindingContext
of the page is set to the DefaultViewModel
property of itself. This property is defined in the code-behind file for the page, and provides a viewmodel instance. The ListView binds to the Employees
property of the viewmodel. The DataTemplate, which defines the appearance of each item in the ListView, contains a Button. The button's Command
property is bound to the DeleteEmployeeCommand
in its parent's viewmodel. Tapping a Button deletes an employee:
In addition, the optional AncestorLevel
property can help disambiguate ancestor lookup in scenarios where there is possibly more than one ancestor of that type in the visual tree:
<Label Text="{Binding Source={RelativeSource AncestorType={x:Type Entry}, AncestorLevel=2}, Path=Text}" />
In this example, the Label.Text
property binds to the Text
property of the second Entry that's encountered on the upward path, starting at the target element of the binding.
Note
The AncestorLevel
property should be set to 1 to find the ancestor nearest to the binding target element.
Bind to a templated parent
The TemplatedParent
relative binding mode is used to bind from within a control template to the runtime object instance to which the template is applied (known as the templated parent). This mode is only applicable if the relative binding is within a control template, and is similar to setting a TemplateBinding
.
The following XAML shows an example of the TemplatedParent
relative binding mode:
<ContentPage ...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Border BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
Stroke="{Binding BorderColor}"
...>
<Grid>
...
<Label Text="{Binding CardTitle}"
... />
<BoxView BackgroundColor="{Binding BorderColor}"
... />
<Label Text="{Binding CardDescription}"
... />
</Grid>
</Border>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout>
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</StackLayout>
</ContentPage>
In this example, the Border, 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 Border and its children resolve their binding expressions against the properties of each CardView
object:
For more information about control templates, see Control templates.