Содержание
Относительная привязка (relative binding) позволяет задавать источник привязки относительно положения целевого объекта в визуальном дереве элементов. Относительные привязки задаются с использованием расширения разметки RelativeSource.
Свойства RelativeSource
В RelativeSource могут использоваться следующие свойства:
| Свойство | Тип | Описание |
Mode |
RelativeBindingSourceMode |
Режим относительной привязки. Может принимать следующие значения:
|
AncestorLevel |
int |
Уровень элементов в визуальном дереве относительно контейнера, где будет вестись поиск объекта-источника привязки (используется, если свойство Mode имеет значение FindAncestor) |
AncestorType |
Type |
Определяет тип элементов, среди которых будет производиться поиск объекта-источника привязки (используется, если свойство Mode имеет значение FindAncestor) |
Рассмотрим как можно использовать относительную привязку в своих приложениях .NET MAUI.
Привязка к самому себе (Mode=Self)
Это наиболее простой режим относительной привязки. Например, напишем следующий код XAML:
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<BoxView WidthRequest="{Binding Source={x:Reference WidthSlider}, Path=Value}"
HeightRequest="{Binding Source={RelativeSource Mode=Self}, Path=WidthRequest}"/>
<Slider Maximum="500" Minimum="10" x:Name="WidthSlider"></Slider>
</VerticalStackLayout>
Здесь свойство WidthRequest элемента BoxView привязано к значению Value слайдера WidthSlider. Здесь мы используем обычную привязку. В свою очередь свойство HeightRequest привязывается к самом себе, а именно — к свойству WidthRequest. Таким образом, и ширина и высота BoxView будут меняться одинаково при изменении значения Value и слайдера:
Относительная привязка к предку (Mode=FindAncestor и Mode=FindAncestorBindingContext)
Режимы FindAncestor и FindAncestorBindingContext используются для привязки к родительским элементам в визуальном дереве. При этом родительский элемент не обязательно должен быть контейнером компоновки.
Режим FindAncestor используется для привязки к родительскому элементу, производному от типа Element, а FindAncestorBindingContext — для привязки к свойству BindingContext родительского элемента. Если при установке привязки свойство Mode явным образом, то возможны два варианта поведения:
- если свойство
AncestorTypeв качестве значения получает объект, производный отElement, то свойствоModeнеявно получает значениеFindAncestor - если свойство
AncestorTypeв качестве значения получает объект, не являющийся наследником от Element, то свойствоModeнеявно получает значениеFindAncestorBindingContext
Например, рассмотрим следующий код:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp14.MainPage"
xmlns:local ="clr-namespace:MauiApp14">
<ContentPage.Resources>
<ResourceDictionary>
<local:SizeConverter x:Key="SizeConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Border WidthRequest="{Binding Source={x:Reference HeightSlider}, Path=Value}"
HeightRequest="{Binding Source={RelativeSource Mode=Self}, Path=WidthRequest}" Background="Green">
<BoxView HeightRequest="{Binding Source={RelativeSource AncestorType={x:Type Border}}, Path=HeightRequest, Converter={StaticResource SizeConverter}}"
WidthRequest="{Binding Source={RelativeSource AncestorType={x:Type Border}}, Path=HeightRequest, Converter={StaticResource SizeConverter}}"
Color="Red"></BoxView>
</Border>
<Slider Maximum="500" Minimum="10" x:Name="HeightSlider"></Slider>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Здесь SizeConverter — это конвертер значений, который выглядит следующим образом:
class SizeConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return (double)value - 20;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Что касается визуальных элементов, то здесь элемент Border является родительским элементом для BoxView:
<Border ....>
<BoxView .....></BoxView>
</Border>
Как и в предыдущем примере с BoxView, у Border свойство ширины привязано к значению Value слайдера, а высоты — к самому себе. Что касается BoxView, то для его свойств установлены две относительные привязки к родителю, то есть к Border:
<BoxView HeightRequest="{Binding Source={RelativeSource AncestorType={x:Type Border}},
Path=HeightRequest,
Converter={StaticResource SizeConverter}}"
WidthRequest="{Binding Source={RelativeSource AncestorType={x:Type Border}},
Path=HeightRequest,
Converter={StaticResource SizeConverter}}"
Color="Red">
</BoxView>
Таким образом, так как Mode в относительной привязке явно не указано, то будет использоваться режим FindAncestor. Теперь можно запустить приложение и убедиться, что оба элемента синхронно изменяют свои размеры:
Итого
Относительная привязка в .NET MAUI позволяет привязываться к объектам и их свойствам относительно положения целевого объекта в визуальном дереве. Используя относительную привязку мы можем привязываться либо к самом себе, либо к родительским элементам.
