Basic bindings
A .NET Multi-platform App UI (.NET MAUI) data binding links a pair of properties between two objects, at least one of which is usually a user-interface object. These two objects are called the target and the source:
- The target is the object (and property) on which the data binding is set.
- The source is the object (and property) referenced by the data binding.
In the simplest case, data flows from the source to the target, which means that the value of the target property is set from the value of the source property. However, in some cases, data can alternatively flow from the target to the source, or in both directions.
Important
The target is always the object on which the data binding is set even if it's providing data rather than receiving data.
Bindings with a binding context
Consider the following XAML example, whose intent is to rotate a Label by manipulating a Slider:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
Without data bindings, you would set the ValueChanged
event of the Slider to an event handler that accesses the Value
property of the Slider and sets that value to the Rotation
property of the Label. The data binding automates this task, and so the event handler and the code within it are no longer necessary.
You can set a binding on an instance of any class that derives from BindableObject, which includes Element, VisualElement, View, and View derivatives. The binding is always set on the target object. The binding references the source object. To set the data binding, use the following two members of the target class:
- The
BindingContext
property specifies the source object. - The
SetBinding
method specifies the target property and source property.
In this example, the Label is the binding target, and the Slider is the binding source. Changes in the Slider source affect the rotation of the Label target. Data flows from the source to the target.
The SetBinding
method defined by BindableObject has an argument of type BindingBase
from which the Binding
class derives, but there are other SetBinding
methods defined by the BindableObjectExtensions
class. The code-behind for the XAML uses a simpler SetBinding
extension method from the BindableObjectExtensions
class:
public partial class BasicCodeBindingPage : ContentPage
{
public BasicCodeBindingPage()
{
InitializeComponent();
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}
The Label object is the binding target so that's the object on which this property is set and on which the method is called. The BindingContext
property indicates the binding source, which is the Slider. The SetBinding
method is called on the binding target but specifies both the target property and the source property. The target property is specified as a BindableProperty object: Label.RotationProperty
. The source property is specified as a string and indicates the Value
property of Slider.
Important
The target property must be backed by a bindable property. Therefore, the target object must be an instance of a class that derives from BindableObject. For more information, see Bindable properties.
The source property is specified as a string. Internally, reflection is used to access the actual property. In this particular case, however, the Value
property is also backed by a bindable property.
As you manipulate the Slider, the Label rotates accordingly:
Alternatively, the data binding can be specified in XAML:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
Just as in code, the data binding is set on the target object, which is the Label. Two XAML markup extensions are used to define the data binding:
- The
x:Reference
markup extension is required to reference the source object, which is the Slider namedslider
. - The
Binding
markup extension links theRotation
property of the Label to theValue
property of the Slider.
For more information about XAML markup extensions, see Consume XAML markup extensions.
Note
The source property is specified with the Path
property of the Binding
markup extension, which corresponds with the Path
property of the Binding
class.
XAML markup extensions such as x:Reference
and Binding
can have content property attributes defined, which for XAML markup extensions means that the property name doesn't need to appear. The Name
property is the content property of x:Reference
, and the Path
property is the content property of Binding
, which means that they can be eliminated from the expressions:
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />
Important
Binding performance can be improved by using compiled bindings. For more information, see Compiled bindings.
Bindings without a binding context
The BindingContext
property is an important component of data bindings, but it is not always necessary. The source object can instead be specified in the SetBinding
call or the Binding
markup extension:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
In this example, the Slider is defined to control the Scale
property of the Label. For that reason, the Slider is set for a range of -2 to 2.
The code-behind file sets the binding with the SetBinding
method, with the second argument being a constructor for the Binding
class:
public partial class AlternativeCodeBindingPage : ContentPage
{
public AlternativeCodeBindingPage()
{
InitializeComponent();
label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));
}
}
The Binding
constructor has 6 parameters, so the source
parameter is specified with a named argument. The argument is the slider
object.
Note
The VisualElement class also defines ScaleX
and ScaleY
properties, which can scale the VisualElement differently in the horizontal and vertical directions.
Alternatively, the data binding can be specified in XAML:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
In this example, the Binding
markup extension has two properties set, Source
and Path
, separated by a comma. The Source
property is set to an embedded x:Reference
markup extension that otherwise has the same syntax as setting the BindingContext
.
The content property of the Binding
markup extension is Path
, but the Path=
part of the markup extension can only be eliminated if it is the first property in the expression. To eliminate the Path=
part, you need to swap the two properties:
Scale="{Binding Value, Source={x:Reference slider}}" />
Although XAML markup extensions are usually delimited by curly braces, they can also be expressed as object elements:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>
In this example, the Source
and Path
properties are regular XAML attributes. The values appear within quotation marks and the attributes are not separated by a comma. The x:Reference
markup extension can also become an object element:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>
This syntax isn't common, but sometimes it's necessary when complex objects are involved.
The examples shown so far set the BindingContext
property and the Source
property of Binding
to an x:Reference
markup extension to reference another view on the page. These two properties are of type Object
, and they can be set to any object that includes properties that are suitable for binding sources. You can also set the BindingContext
or Source
property to an x:Static
markup extension to reference the value of a static property or field, or a StaticResource
markup extension to reference an object stored in a resource dictionary, or directly to an object, which is often an instance of a viewmodel.
Note
The BindingContext
property can also be set to a Binding
object so that the Source
and Path
properties of Binding
define the binding context.
Binding context inheritance
You can specify the source object using the BindingContext
property or the Source
property of the Binding
object. If both are set, the Source
property of the Binding
takes precedence over the BindingContext
.
Important
The BindingContext
property value is inherited through the visual tree.
The following XAML example demonstrates binding context inheritance:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">
<StackLayout VerticalOptions="Fill"
BindingContext="{x:Reference slider}">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="End"
Rotation="{Binding Value}" />
<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="Start"
Rotation="{Binding Value}" />
</StackLayout>
<Slider x:Name="slider"
Maximum="360" />
</StackLayout>
</ContentPage>
In this example, the BindingContext
property of the StackLayout is set to the slider
object. This binding context is inherited by both the Label and the BoxView, both of which have their Rotation
properties set to the Value
property of the Slider: