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

Последнее обновление: 20.12.2022

Относительная привязка в .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 этого же элемента:

Относительная привязка к самому себе в .NET MAUI и C#

Привязка к контейнеру и его контексту

Режимы 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 в реальности будут привязаны к этому объекту.

Относительная привязка к контейнеру в .NET MAUI и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850