Привязка в .NET MAUI. Относительная привязка

Относительная привязка (relative binding) позволяет задавать источник привязки относительно положения целевого объекта в визуальном дереве элементов. Относительные привязки задаются с использованием расширения разметки RelativeSource.

Свойства RelativeSource

В RelativeSource могут использоваться следующие свойства:

Свойство Тип Описание
Mode RelativeBindingSourceMode Режим относительной привязки. Может принимать следующие значения:

  • TemplatedParent — используется для установки привязки внутри шаблона элемента.
  • Self — привязка к самому себе
  • FindAncestor — указывает на контейнер в визуальном дереве элементов, в котором необходимо искать объект-источник привязки.
  • FindAncestorBindingContext — привязка к свойству BindingContext контейнера.
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 явным образом, то возможны два варианта поведения:

  1. если свойство AncestorType в качестве значения получает объект, производный от Element, то свойство Mode неявно получает значение FindAncestor
  2. если свойство 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 позволяет привязываться к объектам и их свойствам относительно положения целевого объекта в визуальном дереве. Используя относительную привязку мы можем привязываться либо к самом себе, либо к родительским элементам.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии