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

Browse sample. Обзор примера

Относительные привязки пользовательского интерфейса приложений .NET (.NET MAUI) позволяют задать источник привязки относительно положения целевого объекта привязки. Они создаются с помощью расширения разметки RelativeSource и задаются в качестве свойства Source выражения привязки.

Расширение разметки RelativeSource поддерживается классом RelativeSourceExtension, определяющим следующие свойства:

  • Mode с типом RelativeBindingSourceMode описывает расположение источника привязки относительно положения целевого объекта привязки.
  • AncestorLevel с типом int является необязательным уровнем предка для поиска, когда свойство Mode имеет значение FindAncestor. AncestorLeveln пропускает n-1 экземпляры AncestorType.
  • AncestorType с типом Type является типом предка для поиска, когда свойство Mode имеет значение FindAncestor.

Примечание.

Средство синтаксического анализа XAML позволяет сократить класс RelativeSourceExtension как RelativeSource.

Для свойства Mode должен быть задан один из членов перечисления RelativeBindingSourceMode.

  • TemplatedParent указывает элемент, к которому применяется шаблон, где существует связанный элемент. Дополнительные сведения см. в разделе Привязка к шаблонному родительскому элементу.
  • Self указывает элемент, в котором настраивается привязка, позволяя привязать одно свойство этого элемента к другому свойству того же элемента. Дополнительные сведения см. в разделе Привязка к самому себе.
  • FindAncestor указывает предка в визуальном дереве связанного элемента. Этот режим следует использовать для привязки к элементу управления предка, представленному свойством AncestorType. Дополнительные сведения см. в разделе Привязка к предку.
  • FindAncestorBindingContext указывает BindingContext предка в визуальном дереве связанного элемента. Этот режим следует использовать для привязки к BindingContext предка, представленному свойством AncestorType. Дополнительные сведения см. в разделе Привязка к предку.

Свойство Mode — это свойство содержимого класса RelativeSourceExtension. Таким образом, для выражений разметки XAML с фигурными скобками можно исключить часть Mode= выражения.

Дополнительные сведения о расширениях разметки .NET MAUI см. в разделе "Использование расширений разметки XAML".

Привязка к самому себе

Режим относительной привязки Self используется для привязки свойства элемента к другому свойству того же элемента:

<BoxView Color="Red"
         WidthRequest="200"
         HeightRequest="{Binding Source={RelativeSource Self}, Path=WidthRequest}"
         HorizontalOptions="Center" />

В этом примере BoxView задает для своего свойства WidthRequest фиксированный размер, а свойство HeightRequest привязывается к свойству WidthRequest. Таким образом, оба свойства равны, поэтому рисуется квадрат:

Screenshot of a Self mode relative binding.

Важно!

При привязке свойства элемента к другому свойству того же элемента эти свойства должны иметь одинаковый тип. Кроме того, в привязке можно указать преобразователь для преобразования значения.

Обычно этот режим привязки используется для того, чтобы задать для BindingContext объекта его же свойство. В приведенном ниже коде показан соответствующий пример:

<ContentPage ...
             BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
    <StackLayout>
        <ListView ItemsSource="{Binding Employees}">
            ...
        </ListView>
    </StackLayout>
</ContentPage>

В этом примере для BindingContext страницы задается его собственное свойство DefaultViewModel. Это свойство определено в файле кода программной части для страницы и предоставляет экземпляр модели представления. ListView привязывается к свойству Employees модели представления.

Привязка к предку

Режимы относительной привязки FindAncestor и FindAncestorBindingContext используются для привязки к родительским элементам определенного типа в визуальном дереве. Режим FindAncestor используется для привязки к родительскому элементу, производному от типа Element. Режим FindAncestorBindingContext используется для привязки к BindingContext родительского элемента.

Предупреждение

При использовании режимов относительной привязки FindAncestor и FindAncestorBindingContext необходимо задать Type для свойства AncestorType, в противном случае возникает исключение XamlParseException.

Если свойство Mode не задано явным образом, задание для свойства AncestorType типа, производного от Element, неявно назначит свойству Mode значение FindAncestor. Аналогичным образом, задание для свойства AncestorType типа, не являющегося производным от Element, неявно назначит свойству Mode значение FindAncestorBindingContext.

Примечание.

Относительные привязки, использующие режим FindAncestorBindingContext, будут повторно применены при изменении BindingContext любых предков.

В следующем коде XAML показан пример, где для свойства Mode будет неявно задано значение FindAncestorBindingContext:

<ContentPage ...
             BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
    <StackLayout>
        <ListView ItemsSource="{Binding Employees}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <Label Text="{Binding Fullname}"
                                   VerticalOptions="Center" />
                            <Button Text="Delete"
                                    Command="{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeleteEmployeeCommand}"
                                    CommandParameter="{Binding}"
                                    HorizontalOptions="End" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

В этом примере для BindingContext страницы задается его собственное свойство DefaultViewModel. Это свойство определено в файле кода программной части для страницы и предоставляет экземпляр модели представления. ListView привязывается к свойству Employees модели представления. DataTemplate, определяющий внешний вид каждого элемента в ListView, содержит Button. Свойство Command кнопки привязано к DeleteEmployeeCommand в модели представления его родительского элемента. При нажатии Button удаляется сотрудник:

Screenshot of a FindAncestor mode relative binding.

Кроме того, необязательное свойство AncestorLevel может помочь устранить неоднозначность поиска предка в случаях, где в визуальном дереве может существовать более одного предка данного типа:

<Label Text="{Binding Source={RelativeSource AncestorType={x:Type Entry}, AncestorLevel=2}, Path=Text}" />

В этом примере свойство Label.Text привязывается к свойству Text второго Entry, обнаруженному на пути вверх, начиная с целевого объекта привязки.

Примечание.

Свойству AncestorLevel должно быть назначено значение 1, чтобы найти предка, ближайшего к целевому объекту привязки.

Привязка к шаблонному родительскому элементу

Режим относительной привязки TemplatedParent используется для привязки из шаблона элемента управления к экземпляру объекта среды выполнения, к которому применяется этот шаблон (также называется шаблонным родительским элементом). Этот режим применим только в том случае, если относительная привязка находится внутри шаблона элемента управления и аналогична заданию TemplateBinding.

Ниже представлен пример XAML для относительной привязки TemplatedParent:

<ContentPage ...>
    <ContentPage.Resources>
        <ControlTemplate x:Key="CardViewControlTemplate">
            <Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
                   BackgroundColor="{Binding CardColor}"
                   BorderColor="{Binding BorderColor}"
                   ...>
                <Grid>
                    ...
                    <Label Text="{Binding CardTitle}"
                           ... />
                    <BoxView BackgroundColor="{Binding BorderColor}"
                             ... />
                    <Label Text="{Binding CardDescription}"
                           ... />
                </Grid>
            </Frame>
        </ControlTemplate>
    </ContentPage.Resources>
    <StackLayout>        
        <controls:CardView BorderColor="DarkGray"
                           CardTitle="John Doe"
                           CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
                           IconBackgroundColor="SlateGray"
                           IconImageSource="user.png"
                           ControlTemplate="{StaticResource CardViewControlTemplate}" />
        <controls:CardView BorderColor="DarkGray"
                           CardTitle="Jane Doe"
                           CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
                           IconBackgroundColor="SlateGray"
                           IconImageSource="user.png"
                           ControlTemplate="{StaticResource CardViewControlTemplate}" />
        <controls:CardView BorderColor="DarkGray"
                           CardTitle="Xamarin Monkey"
                           CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
                           IconBackgroundColor="SlateGray"
                           IconImageSource="user.png"
                           ControlTemplate="{StaticResource CardViewControlTemplate}" />
    </StackLayout>
</ContentPage>

В этом примере Frame, являющийся корневым элементом ControlTemplate, имеет BindingContext, для которого установлен экземпляр объекта среды выполнения, к которому применяется шаблон. Таким образом, Frame и его дочерние элементы разрешают свои выражения привязки для свойств каждого объекта CardView:

Screenshot of a TemplatedParent mode relative binding.

Дополнительные сведения о шаблонах элементов управления см. в разделе "Шаблоны элементов управления".