Enlace de ruta de acceso de Xamarin.Forms
En todos los ejemplos de enlace de datos anteriores, la propiedad Path
de la clase Binding
(o la propiedad Path
de la extensión de marcado Binding
) se había establecido en una sola propiedad. En realidad es posible establecer Path
en una subpropiedad (una propiedad de una propiedad), o bien en un miembro de una colección.
Por ejemplo, suponga que la página contiene un control TimePicker
:
<TimePicker x:Name="timePicker">
La propiedad Time
de TimePicker
es de tipo TimeSpan
, pero es posible que quiera crear un enlace de datos que haga referencia a la propiedad TotalSeconds
de ese valor TimeSpan
. Este es el enlace de datos:
{Binding Source={x:Reference timePicker},
Path=Time.TotalSeconds}
La propiedad Time
es de tipo TimeSpan
, que tiene una propiedad TotalSeconds
. Las propiedades Time
y TotalSeconds
se conectan simplemente con un punto. Los elementos de la cadena Path
siempre hacen referencia a propiedades y no a los tipos de estas propiedades.
Ese y otros muchos ejemplos se muestran en la página Variaciones de la ruta de acceso:
<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>
En el segundo control Label
, el origen de enlace es la propia página. La propiedad Content
es de tipo StackLayout
, que tiene una propiedad Children
de tipo IList<View>
, que a su vez tiene una propiedad Count
que indica el número de elementos secundarios.
Rutas de acceso con indizadores
El enlace en el tercer control Label
de las páginas Variaciones de la ruta de acceso hace referencia a la clase CultureInfo
del espacio de nombres System.Globalization
:
<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />
El origen se establece en la propiedad estática CultureInfo.CurrentCulture
, que es un objeto de tipo CultureInfo
. Esa clase define una propiedad denominada DateTimeFormat
de tipo DateTimeFormatInfo
que contiene una colección DayNames
. El índice selecciona el cuarto elemento.
El cuarto control Label
hace algo similar pero para la referencia cultural asociada con Francia. La propiedad Source
del enlace se establece en el objeto CultureInfo
con un constructor:
<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>
Vea Pasar argumentos de constructor para obtener más información sobre cómo especificar argumentos de constructor en XAML.
El último ejemplo es similar al segundo, salvo que hace referencia a uno de los elementos secundarios del elemento StackLayout
:
<Label Text="{Binding Source={x:Reference page},
Path=Content.Children[1].Text.Length,
StringFormat='The first Label has {0} characters'}" />
Ese elemento secundario es un control Label
, que tiene una propiedad Text
de tipo String
, que a su vez tiene una propiedad Length
. El primer objeto Label
notifica el valor TimeSpan
establecido en el elemento TimePicker
, de modo que cuando se cambia el texto, el último objeto Label
también cambia.
Esta es la ejecución del programa:
Depuración de rutas de acceso complejas
Las definiciones de ruta de acceso complejas pueden ser difíciles de construir: necesita saber el tipo de cada subpropiedad o el tipo de los elementos de la colección para agregar correctamente la subpropiedad siguiente, pero los propios tipos no aparecen en la ruta de acceso. Una técnica adecuada consiste en crear la ruta de acceso de forma incremental y observar los resultados intermedios. Para ese último ejemplo, se podría empezar sin ninguna definición de Path
:
<Label Text="{Binding Source={x:Reference page},
StringFormat='{0}'}" />
Eso muestra el tipo del origen de enlace, o DataBindingDemos.PathVariationsPage
. Ya sabe que PathVariationsPage
se deriva de ContentPage
, por lo que tiene una propiedad Content
:
<Label Text="{Binding Source={x:Reference page},
Path=Content,
StringFormat='{0}'}" />
Ahora, se revela que el tipo de la propiedad Content
es Xamarin.Forms.StackLayout
. Agregue la propiedad Children
a Path
y el tipo será Xamarin.Forms.ElementCollection'1[Xamarin.Forms.View]
, que es una clase interna para Xamarin.Forms, pero obviamente un tipo de colección. Agregue un índice a lo anterior y el tipo será Xamarin.Forms.Label
. Continúe de esta manera.
A medida que Xamarin.Forms procesa la ruta de acceso de enlace, instala un controlador PropertyChanged
en todos los objetos de la ruta de acceso que implementen la interfaz INotifyPropertyChanged
. Por ejemplo, el enlace final reacciona ante un cambio en el primer objeto Label
porque cambia la propiedad Text
.
Si una propiedad en la ruta de acceso de enlace no implementa INotifyPropertyChanged
, se omitirán todos los cambios a esa propiedad. Algunos cambios podrían invalidar completamente la ruta de acceso de enlace, por lo que solo debe usar esta técnica cuando la cadena de propiedades y subpropiedades nunca sea no válida.