Enlace de ruta de acceso de Xamarin.Forms

Download SampleDescargar el ejemplo

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:

Path Variations

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.