Относительная привязка в .NET MAUI позволяют задать источник привязки относительно положения целевого объекта привязки в визуальном дереве элементов.
Для создания относительной привязки применяется расширения разметки RelativeSource. оно имеет следующие свойства:
Mode: представляет тип RelativeBindingSourceMode
и устанавливает режим привязки. Данное свойство может принимать следующие
значения:
TemplatedParent
: применяется для установки привязки внутри шаблона элемента.
Self
: указывает на привязку к самому себе
FindAncestor
: указывает на контейнер в визуальном дереве элементов, где надо искать объект-источник привязки.
FindAncestorBindingContext
: привзяка будет идти к свойству BindingContext
контейнера.
AncestorLevel: представляет уровень элементов в визуальном дереве относительно контейнера, где будет идти поиск объекта-источника привязки
(если свойство Mode
имеет значение FindAncestor
)
AncestorType: представляет тип Type
и указывает на тип элементов, среди которых будет идти поиск объекта-источника привязки
(если свойство Mode
имеет значение FindAncestor
)
Для привязки к самому себе применяется режим Self
. Например, пусть у нас есть класс конвертера из строки в цвет:
using System.Globalization; public class StringToColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (Color.TryParse(value.ToString(), out var color)) return color; else return Colors.Black; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return ((Color)value).ToHex(); } }
Привяжем свойство TextColor элемента Entry к его свойству Text и для конвертации строки в цвет используем выше определенный конвертер:
<?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" xmlns:local="clr-namespace:HelloApp" x:Class="HelloApp.MainPage"> <ContentPage.Resources> <local:StringToColorConverter x:Key="converter" /> </ContentPage.Resources> <StackLayout Padding="10"> <Entry Text="#000" TextColor="{Binding Source={RelativeSource Self}, Path=Text, Converter={StaticResource converter}}"/> </StackLayout> </ContentPage>
Благодаря выражению Source={RelativeSource Self}
свойство TextColor будет привязано к свойству Text этого же элемента:
Режимы FindAncestor и FindAncestorBindingContext применяются для привязки к родительским элементам определенного типа в визуальном дереве. Режим FindAncestor используется для привязки к родительскому элементу, производному от типа Element. Режим FindAncestorBindingContext используется для привязки к BindingContext родительского элемента.
Если при установи привязки свойство Mode
явным образом не задано, то есть два сценария:
Свойство AncestorType в качестве значения получает объект, производный от Element.
В этом случае свойство Mode
неявно получает значение FindAncestor
Свойство AncestorType в качестве значения получает объект, НЕпроизводный от Element.
В этом случае свойство Mode
неявно получает значение FindAncestorBindingContext
Допустим, у нас есть следующий класс Person:
using System.ComponentModel; using System.Runtime.CompilerServices; namespace HelloApp; public class Person : INotifyPropertyChanged { string name = ""; int age; public event PropertyChangedEventHandler PropertyChanged; public string Name { get => name; set { if (name != value) { name = value; OnPropertyChanged(); } } } public int Age { get => age; set { if (age != value) { age = value; OnPropertyChanged(); } } } public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } }
Пусть, контейнер StackLayout привязан к объекту Person, а вложенные элементы Label привязаны к StackLayout
<?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" xmlns:local="clr-namespace:HelloApp" x:Class="HelloApp.MainPage"> <ContentPage.Resources> <local:Person x:Key="tom" Name="Tom" Age="38" /> </ContentPage.Resources> <StackLayout Padding="10" BindingContext="{x:StaticResource person}"> <Label Text="{Binding Source={RelativeSource AncestorType={x:Type local:Person}}, Path=Name}"/> <Label Text="{Binding Source={RelativeSource AncestorType={x:Type local:Person}}, Path=Age}"/> </StackLayout> </ContentPage>
Здесь для обоих элементов Label режим относительной привязки явным образом НЕ задан, а в качестве типа указан локальный тип Person:
AncestorType={x:Type local:Person}
Класс Person НЕ является производным от класса Element, поэтому привязка будет идти к свойству BindingContext
контейнера StackLayout.
А это свойство, в свою очередь, привязано к ресурсу tom
<local:Person x:Key="tom" Name="Tom" Age="38" />
Соответственно метки Label в реальности будут привязаны к этому объекту.