Xamarin.Forms 绑定路径
在前面的所有数据绑定示例中,Binding
类的 Path
属性(或 Binding
标记扩展的 Path
属性)已设置为单个属性。 实际上,可以将 Path
设置为“子属性”(属性的属性),也可以设置为集合的成员。
例如,假定你的页面包含 TimePicker
:
<TimePicker x:Name="timePicker">
TimePicker
的 Time
属性为 TimeSpan
类型,但你可能希望创建引用该 TimeSpan
值的 TotalSeconds
属性的数据绑定。 数据绑定如下:
{Binding Source={x:Reference timePicker},
Path=Time.TotalSeconds}
Time
属性的类型是 TimeSpan
,该类型具有 TotalSeconds
属性。 Time
和 TotalSeconds
属性之间仅用一个句点连接。 Path
字符串中的项始终引用属性,而不是这些属性的类型。
“路径变化”页中显示了该示例和其他几个示例:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:globe="clr-namespace:System.Globalization;assembly=netstandard"
x:Class="DataBindingDemos.PathVariationsPage"
Title="Path Variations"
x:Name="page">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="Large" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="10, 0">
<TimePicker x:Name="timePicker" />
<Label Text="{Binding Source={x:Reference timePicker},
Path=Time.TotalSeconds,
StringFormat='{0} total seconds'}" />
<Label Text="{Binding Source={x:Reference page},
Path=Content.Children.Count,
StringFormat='There are {0} children in this StackLayout'}" />
<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />
<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>
<Label Text="{Binding Source={x:Reference page},
Path=Content.Children[1].Text.Length,
StringFormat='The second Label has {0} characters'}" />
</StackLayout>
</ContentPage>
在第二个 Label
中,绑定源是页面本身。 Content
属性为 StackLayout
类型,它具有 IList<View>
类型(具有指示子级数目的 Count
属性)的 Children
属性。
使用索引器的路径
“路径变化”页中的第三个 Label
中的绑定引用 System.Globalization
命名空间中的 CultureInfo
类:
<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />
源设置为静态 CultureInfo.CurrentCulture
属性,该属性是 CultureInfo
类型的对象。 该类定义 DateTimeFormatInfo
类型的名为 DateTimeFormat
的属性,该属性包含 DayNames
集合。 索引选择第四项。
第四个 Label
执行一些类似的操作,但这些操作仅针对与法国关联的区域性。 绑定的 Source
属性设置为具有构造函数的 CultureInfo
对象:
<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>
有关使用 XAML 指定构造函数参数的详细信息,请参阅传递构造函数参数。
最后一个示例与第二个相似,只不过它引用了 StackLayout
的一个子级:
<Label Text="{Binding Source={x:Reference page},
Path=Content.Children[1].Text.Length,
StringFormat='The first Label has {0} characters'}" />
该子级是 Label
,它具有含 Length
属性的 String
类型的 Text
属性。 第一个 Label
报告 TimePicker
中的 TimeSpan
集,因此当该文本更改时,最后的 Label
也随之更改。
下面是正在运行的程序:
调试复杂路径
复杂路径的定义可能很难构造:你需要知道每个子属性的类型或集合中项的类型,以便正确地添加下一个子属性,但是类型本身不会出现在路径中。 较好的方式是以增量方式逐步构建路径并查看中间结果。 对于上一个示例,你可以从完全没有 Path
定义开始:
<Label Text="{Binding Source={x:Reference page},
StringFormat='{0}'}" />
这将显示绑定源的类型,即 DataBindingDemos.PathVariationsPage
。 你知道 PathVariationsPage
派生自 ContentPage
,所以它有一个 Content
属性:
<Label Text="{Binding Source={x:Reference page},
Path=Content,
StringFormat='{0}'}" />
Content
属性的类型现在显示为 Xamarin.Forms.StackLayout
。 将 Children
属性添加到 Path
中,类型为 Xamarin.Forms.ElementCollection'1[Xamarin.Forms.View]
(它是 Xamarin.Forms 内部的类),显然是集合类型。 向它添加索引,类型为 Xamarin.Forms.Label
。 按这种方式继续操作。
当 Xamarin.Forms 处理绑定路径时,它会在路径中实现 INotifyPropertyChanged
接口的任何对象上安装 PropertyChanged
处理程序。 例如,由于 Text
属性更改,最终的绑定对第一个 Label
中的更改作出反应。
如果绑定路径中的属性没有实现 INotifyPropertyChanged
,那么对该属性的任何更改都将被忽略。 一些更改可能会使绑定路径完全无效,所以应只在属性和子属性字符串永远不会失效的情况下才使用这种技术。