Xamarin.Forms 相对绑定Xamarin.Forms Relative Bindings

下载示例 下载示例Download Sample Download the sample

利用相对绑定,可以设置相对于绑定目标位置的绑定源。Relative bindings provide the ability to set the binding source relative to the position of the binding target. 它们使用 RelativeSource 标记扩展创建,并设置为绑定表达式的 Source 属性。They are created with the RelativeSource markup extension, and set as the Source property of a binding expression.

RelativeSourceExtension 类支持 RelativeSource 标记扩展,并定义以下属性:The RelativeSource markup extension is supported by the RelativeSourceExtension class, which defines the following properties:

  • Mode,属于 RelativeBindingSourceMode 类型,描述相对于绑定目标位置的绑定源位置。Mode, of type RelativeBindingSourceMode, describes the location of the binding source relative to the position of the binding target.
  • AncestorLevel,属于 int 类型,这是要查找的可选上级级别(如果 Mode 属性为 FindAncestor)。AncestorLevel, of type int, an optional ancestor level to look for, when the Mode property is FindAncestor.
  • AncestorType,属于 Type 类型,这是要查找的上级类型(如果 Mode 属性为 FindAncestor)。AncestorType, of type Type, the type of ancestor to look for, when the Mode property is FindAncestor.

备注

XAML 分析程序允许将 RelativeSourceExtension 类缩写为 RelativeSourceThe XAML parser allows the RelativeSourceExtension class to be abbreviated as RelativeSource.

Mode 属性应设置为 RelativeBindingSourceMode 枚举成员之一:The Mode property should be set to one of the RelativeBindingSourceMode enumeration members:

  • TemplatedParent 指示应用了存在绑定元素的模板的元素。TemplatedParent indicates the element to which the template, in which the bound element exists, is applied. 有关详细信息,请参阅绑定到模板化父级For more information, see Bind to a templated parent.
  • Self 指示正在其上设置绑定的元素,并允许你将该元素的一个属性绑定到同一元素的其他属性上。Self indicates the element on which the binding is being set, allowing you to bind one property of that element to another property on the same element. 有关详细信息,请参阅绑定到自身For more information, see Bind to self.
  • FindAncestor 指示绑定元素的可视化树中的上级。FindAncestor indicates the ancestor in the visual tree of the bound element. 此模式应该用于绑定到由 AncestorType 属性表示的上级控件。This mode should be used to bind to an ancestor control represented by the AncestorType property. 有关详细信息,请参阅绑定到上级For more information, see Bind to an ancestor.
  • FindAncestorBindingContext 指示绑定元素可视化树中上级的 BindingContextFindAncestorBindingContext indicates the BindingContext of the ancestor in the visual tree of the bound element. 此模式应该用于绑定到由 AncestorType 属性表示的上级的 BindingContextThis mode should be used to bind to the BindingContext of an ancestor represented by the AncestorType property. 有关详细信息,请参阅绑定到上级For more information, see Bind to an ancestor.

Mode 属性是 RelativeSourceExtension 的内容属性。The Mode property is the content property of the RelativeSourceExtension class. 因此,对于用大括号表示的 XAML 标记表达式,可以删除这类表达式的 Mode= 部分。Therefore, for XAML markup expressions expressed with curly braces, you can eliminate the Mode= part of the expression.

有关 Xamarin.Forms 标记扩展的详细信息,请参阅 XAML 标记扩展For more information about Xamarin.Forms markup extensions, see XAML Markup Extensions.

绑定到自身Bind to self

Self 相对绑定模式用于将某一元素的属性绑定到该元素的其他属性:The Self relative binding mode is used bind a property of an element to another property on the same element:

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

在此示例中,BoxView 将其 WidthRequest 属性设置为固定大小,并将 HeightRequest 属性绑定到 WidthRequest 属性。In this example, the BoxView sets its WidthRequest property to a fixed size, and the HeightRequest property binds to the WidthRequest property. 因此,这两个属性都相等,并绘制正方形:Therefore, both properties are equal and so a square is drawn:

iOS 和 Android 上的 Self 模式相对绑定的屏幕截图Screenshot of a Self mode relative binding, on iOS and Android

重要

将某一元素的属性绑定到该元素的其他属性时,这些属性必须是相同的类型。When binding a property of an element to another property on the same element, the properties must be the same type. 此外,也可以在绑定上指定转换器以转换值。Alternatively, you can specify a converter on the binding to convert the value.

此绑定模式的常见用法是将对象的 BindingContext 设置为其自身的属性。A common use of this binding mode is set an object's BindingContext to a property on itself. 下面的代码显示了此用法的示例:The following code shows an example of this:

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

在此示例中,页面的 BindingContext 设置为其自身的 DefaultViewModel 属性。In this example, the BindingContext of the page is set to the DefaultViewModel property of itself. 此属性在页面的代码隐藏文件中进行定义,并提供 viewmodel 实例。This property is defined in the code-behind file for the page, and provides a viewmodel instance. ListView 绑定到 viewmodel 的 Employees 属性。The ListView binds to the Employees property of the viewmodel.

绑定到上级Bind to an ancestor

FindAncestorFindAncestorBindingContext 相对绑定模式用于绑定到可视化树中特定类型的父元素。The FindAncestor and FindAncestorBindingContext relative binding modes are used to bind to parent elements, of a certain type, in the visual tree. FindAncestor 模式用于绑定到父元素,父元素派生自 Element 类型。The FindAncestor mode is used to bind to a parent element, which derives from the Element type. FindAncestorBindingContext 模式用于绑定到父元素的 BindingContextThe FindAncestorBindingContext mode is used to bind to the BindingContext of a parent element.

警告

使用 FindAncestorFindAncestorBindingContext 相对绑定模式时,必须将 AncestorType 属性设置为 Type,否则将引发 XamlParseExceptionThe AncestorType property must be set to a Type when using the FindAncestor and FindAncestorBindingContext relative binding modes, otherwise a XamlParseException is thrown.

如果未显式设置 Mode 属性,在将 AncestorType 属性设置为派生自 Element 的类型时,会将 Mode 属性隐式设置为 FindAncestorIf the Mode property isn't explicitly set, setting the AncestorType property to a type that derives from Element will implicitly set the Mode property to FindAncestor. 同样,如果将 AncestorType 属性设置为不是派生自 Element 的类型,则会将 Mode 属性隐式设置为 FindAncestorBindingContextSimilarly, setting the AncestorType property to a type that does not derive from Element will implicitly set the Mode property to FindAncestorBindingContext.

下面的 XAML 演示了一个示例,其中 Mode 属性将被隐式设置为 FindAncestorBindingContextThe following XAML shows an example where the Mode property will be implicitly set to 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="EndAndExpand" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

在此示例中,页面的 BindingContext 设置为其自身的 DefaultViewModel 属性。In this example, the BindingContext of the page is set to the DefaultViewModel property of itself. 此属性在页面的代码隐藏文件中进行定义,并提供 viewmodel 实例。This property is defined in the code-behind file for the page, and provides a viewmodel instance. ListView 绑定到 viewmodel 的 Employees 属性。The ListView binds to the Employees property of the viewmodel. DataTemplate 定义 ListView 中各个项的外观,它包含 ButtonThe DataTemplate, which defines the appearance of each item in the ListView, contains a Button. 按钮的 Command 属性绑定到其父级 viewmodel 中的 DeleteEmployeeCommandThe button's Command property is bound to the DeleteEmployeeCommand in its parent's viewmodel. 点击 Button 会删除员工:Tapping a Button deletes an employee:

iOS 和 Android 上的 FindAncestor 模式相对绑定的屏幕截图Screenshot of a FindAncestor mode relative binding, on iOS and Android

此外,当可视化树中可能存在多个该类型的上级时,可以使用可选属性 AncestorLevel 帮助消除上级查找的歧义:In addition, the optional AncestorLevel property can help disambiguate ancestor lookup in scenarios where there is possibly more than one ancestor of that type in the visual tree:

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

在本例中,Label.Text 属性绑定到上行路径上从绑定的目标元素开始,遇到的第二个 EntryText 属性,。In this example, the Label.Text property binds to the Text property of the second Entry that's encountered on the upward path, starting at the target element of the binding.

备注

AncestorLevel 属性应设置为 1,以查找最靠近绑定目标元素的上级。The AncestorLevel property should be set to 1 to find the ancestor nearest to the binding target element.

绑定到模板化父级Bind to a templated parent

TemplatedParent 相对绑定模式用于从控件模板内绑定到应用该模板的运行时对象实例(称为模板化父级)。The TemplatedParent relative binding mode is used to bind from within a control template to the runtime object instance to which the template is applied (known as the templated parent). 仅当相对绑定在控件模板中时,此模式才适用,并且与设置 TemplateBinding 类似。This mode is only applicable if the relative binding is within a control template, and is similar to setting a TemplateBinding.

以下 XAML 显示 TemplatedParent 相对绑定模式的一个示例:The following XAML shows an example of the TemplatedParent relative binding mode:

<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>

在此示例中,FrameControlTemplate 的根元素)将其 BindingContext 设置为应用了该模板的运行时对象实例。In this example, the Frame, which is the root element of the ControlTemplate, has its BindingContext set to the runtime object instance to which the template is applied. 因此,Frame 及其子级针对每个 CardView 对象的属性解析其绑定表达式:Therefore, the Frame and its children resolve their binding expressions against the properties of each CardView object:

iOS 和 Android 上的 TemplatedParent 模式相对绑定的屏幕截图Screenshot of a TemplatedParent mode relative binding, on iOS and Android

有关控件模板的详细信息,请参阅 Xamarin.Forms 控件模板For more information about control templates, see Xamarin.Forms Control Templates.