Enlaces compilados de Xamarin.Forms

Los enlaces compilados se resuelven más rápidamente que los enlaces clásicos, lo cual mejora el rendimiento del enlace de datos en las aplicaciones de Xamarin.Forms.

Los enlaces de datos tienen dos problemas principales:

  1. No hay ninguna validación de las expresiones de enlace en tiempo de compilación. Alternativamente, los enlaces se resuelven en tiempo de ejecución. Por lo tanto, los enlaces no válidos no se detectan hasta el tiempo de ejecución, cuando la aplicación no se comporta según lo esperado o aparecen mensajes de error.
  2. No son rentables. Los enlaces se resuelven en tiempo de ejecución mediante la inspección de objetos de uso general (reflejo); el trabajo adicional que supone llevarlo a cabo varía en función de la plataforma.

Los enlaces compilados mejoran el rendimiento de enlace de datos en las aplicaciones de Xamarin.Forms mediante la resolución de expresiones de enlace en tiempo de compilación, en lugar de en tiempo de ejecución. Además, esta validación en tiempo de compilación de expresiones de enlace permite una mejor experiencia de solución de problemas, porque los enlaces no válidos se notifican como errores de compilación.

El proceso para usar enlaces compilados es el siguiente:

  1. Habilite la compilación XAML. Para obtener más información acerca de la compilación XAML, consulte XAML Compilation (Compilación XAML).
  2. Establezca un atributo x:DataType de un elemento VisualElement para el tipo del objeto al cual VisualElement y sus elementos secundarios se enlazará.

Nota:

Se recomienda establecer el atributo x:DataType en el mismo nivel de la jerarquía de vistas en que está establecido BindingContext. Sin embargo, este atributo puede volver a definirse en cualquier ubicación en una jerarquía de vistas.

Para usar enlaces compilados, el atributo x:DataType debe establecerse en un literal de cadena o un tipo con la extensión de marcado x:Type. En tiempo de compilación XAML, las expresiones de enlace no válidas se notificarán como errores de compilación. Sin embargo, el compilador XAML solo notificará un error de compilación para la primera expresión de enlace no válida que encuentre. Las expresiones de enlace válidas que se definen en VisualElement o en sus elementos secundarios se compilarán, independientemente de si BindingContext está establecido en XAML o en código. La compilación de una expresión de enlace genera un código compilado que obtendrá un valor de una propiedad en el origen y lo establecerá en la propiedad en el destino que se especifica en el marcado. Además, dependiendo de la expresión de enlace, el código generado puede observar cambios en el valor de la propiedad de origen y actualizar la propiedad de destino, y puede insertar los cambios desde el destino de nuevo al origen.

Importante

Los enlaces compilados actualmente están deshabilitados para las expresiones de enlace que definen la propiedad Source. Esto es así porque la propiedad Source siempre se establece mediante la extensión de marcado x:Reference, que no se puede resolver en tiempo de compilación.

Uso de enlaces compilados

En la página Compiled Color Selector (Selector de colores compilados) se muestra el uso de enlaces compilados entre las vistas de Xamarin.Forms y las propiedades de modelo de vista:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorSelectorPage"
             Title="Compiled Color Selector">
    ...
    <StackLayout x:DataType="local:HslColorViewModel">
        <StackLayout.BindingContext>
            <local:HslColorViewModel Color="Sienna" />
        </StackLayout.BindingContext>
        <BoxView Color="{Binding Color}"
                 ... />
        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />
            <Slider Value="{Binding Hue}" />
            <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
            <Slider Value="{Binding Saturation}" />
            <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
            <Slider Value="{Binding Luminosity}" />
            <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
        </StackLayout>
    </StackLayout>    
</ContentPage>

El elemento StackLayout raíz crea una instancia de HslColorViewModel e inicializa la propiedad Color dentro de las etiquetas de elemento de propiedad para la propiedad BindingContext. El elemento StackLayout raíz también define el atributo x:DataType como el tipo ViewModel, lo cual indica que todas las expresiones de enlace en la jerarquía de vistas StackLayout raíz se compilarán. Esto se puede comprobar cambiando cualquiera de las expresiones de enlace para enlazar a una propiedad ViewModel inexistente, lo cual generará a un error de compilación. Aunque en este ejemplo se establece el atributo x:DataType en un literal de cadena, también se puede establecer en un tipo con la extensión de marcado x:Type. Para obtener más información acerca de la extensión de marcado x:Type, consulte x:Type Markup Extension (Extensión de marcado x:Type).

Importante

El atributo x:DataType puede volver a definirse en cualquier punto de una jerarquía de vistas.

Los elementos BoxView, Label y las vistas Slider heredan el contexto de enlace del elemento StackLayout. Todas estas vistas son destinos de enlace que hacen referencia a las propiedades de origen en el modelo de vista. Para la propiedad BoxView.Color y la propiedad Label.Text, los enlaces de datos son OneWay; las propiedades de las vista se establecen a partir de las propiedades en ViewModel. Sin embargo, la propiedad Slider.Value utiliza un enlace TwoWay. Esto permite que cada elemento Slider se establezca a partir del modelo de vista, y también que el modelo de vista se establezca a partir de cada elemento Slider.

Cuando la aplicación se ejecuta por primera vez, los elementos BoxView, Label, y los elementos Slider están establecidos a partir de ViewModel en base a la propiedad Color inicial establecida cuando se creó una instancia de ViewModel. Esto se muestra en las capturas de pantalla siguientes:

Selector de colores compilados

A medida que se manipulan los controles deslizantes, los elementos BoxView y Label se actualizan del modo correspondiente.

Para obtener más información acerca de este selector de colores, consulte ViewModels and Property-Change Notifications (ViewModels y las notificaciones de cambio de propiedad).

Uso de enlaces compilados en DataTemplate

Los enlaces en DataTemplate se interpretan en el contexto del objeto del cual se crea la plantilla. Por lo tanto, cuando utilice enlaces de compilación en DataTemplate, DataTemplate debe declarar el tipo de su objeto de datos mediante el atributo x:DataType.

En la página Compiled Color List (Lista de colores compilados) se muestra el uso de enlaces compilados en DataTemplate:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorListPage"
             Title="Compiled Color List">
    <Grid>
        ...
        <ListView x:Name="colorListView"
                  ItemsSource="{x:Static local:NamedColor.All}"
                  ... >
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:NamedColor">
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <BoxView Color="{Binding Color}"
                                     ... />
                            <Label Text="{Binding FriendlyName}"
                                   ... />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <!-- The BoxView doesn't use compiled bindings -->
        <BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
                 ... />
    </Grid>
</ContentPage>

La propiedad ListView.ItemsSource está establecida en la propiedad NamedColor.All estática. La clase NamedColor usa la fijación de .NET para enumerar todos los campos públicos estáticos en la estructura de Color y almacenarlos con sus nombres en una colección que sea accesible desde la propiedad All estática. Por lo tanto, ListView se rellena con todas las instancias de NamedColor. Para cada elemento de ListView, el contexto de enlace para el elemento está establecido en un objeto NamedColor. Los elementos BoxView y Label de ViewCell están enlazados a propiedades NamedColor.

Tenga en cuenta que DataTemplatex:DataTypeNamedColor define el atributo para ser del tipo DataTemplate, lo cual indica que todas las expresiones de enlace en la jerarquía de vistas se compilarán. Esto se puede comprobar cambiando cualquiera de las expresiones de enlace para enlazar a una propiedad NamedColor inexistente, lo cual generará a un error de compilación. Aunque en este ejemplo se establece el atributo x:DataType en un literal de cadena, también se puede establecer en un tipo con la extensión de marcado x:Type. Para obtener más información acerca de la extensión de marcado x:Type, consulte x:Type Markup Extension (Extensión de marcado x:Type).

Cuando la aplicación se ejecuta por primera vez, ListView se rellena con instancias de NamedColor. Cuando un elemento de ListView está seleccionado, la propiedad BoxView.Color se establece en el color del elemento seleccionado en ListView:

Lista de colores compilados

Al seleccionar otros elementos de ListView se actualiza el color de BoxView.

Combinación de enlaces compilados con enlaces clásicos

Las expresiones de enlace solo se compilan para la jerarquía de vistas en la cual está definido el atributo x:DataType. Por contra, todas las vistas en una jerarquía en la cual el atributo x:DataType no esté definido utilizarán enlaces clásicos. Por lo tanto, es posible combinar enlaces compilados y enlaces clásicos en una página. Por ejemplo, en la sección anterior, las vistas dentro de DataTemplate utilizan enlaces compilados, mientras que el elemento BoxView que se establece en el color seleccionado en ListView, no lo hace.

Una estructuración cuidadosa de atributos x:DataType, por lo tanto, puede conseguir que una página utilice enlaces compilados y clásicos. De forma alternativa, el atributo x:DataType se puede volver a definir en cualquier punto en una jerarquía de vistas para null utilizando la extensión de marcado x:Null. Esto indica que las expresiones de enlace dentro de la jerarquía de vistas utilizarán enlaces clásicos. La página Mixed Bindings (Enlaces mixtos) muestra este enfoque:

<StackLayout x:DataType="local:HslColorViewModel">
    <StackLayout.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </StackLayout.BindingContext>
    <BoxView Color="{Binding Color}"
             VerticalOptions="FillAndExpand" />
    <StackLayout x:DataType="{x:Null}"
                 Margin="10, 0">
        <Label Text="{Binding Name}" />
        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</StackLayout>   

El elemento StackLayout raíz establece el atributo x:DataType para ser del tipo HslColorViewModel, lo cual indica que todas las expresiones de enlace en la jerarquía de vistas StackLayout se compilarán. Sin embargo, el StackLayout interno redefine el atributo x:DataType en null con la expresión de marcado x:Null. Por lo tanto, las expresiones de enlace dentro del StackLayout interno usan enlaces clásicos. Solo BoxView, dentro de la jerarquía de vistas StackLayout raíz, utiliza enlaces compilados.

Para obtener más información acerca de la expresión de marcado x:Null, consulte x:Null Markup Extension (Extensión de marcado x:Null).

Rendimiento

Los enlaces compilados mejoran el rendimiento del enlace de datos, con unas ventajas de rendimiento variables. Las pruebas de unidades muestran lo siguiente:

  • Un enlace compilado que utiliza la notificación de cambio de propiedad (es decir, un enlace OneWay, OneWayToSource o TwoWay) se resuelve aproximadamente 8 veces más rápidamente que un enlace clásico.
  • Un enlace compilado que no utiliza la notificación de cambio de propiedad (es decir, un enlace OneTime) se resuelve aproximadamente 20 veces más rápidamente que un enlace clásico.
  • El establecimiento de BindingContext en un enlace compilado que utiliza la notificación de cambio de propiedad (es decir, un enlace OneWay, OneWayToSource o TwoWay) se resuelve aproximadamente 5 veces más rápidamente que el establecimiento de BindingContext en un enlace clásico.
  • El establecimiento de BindingContext en un enlace compilado que no utiliza la notificación de cambio de propiedad (es decir, un enlace OneTime) se resuelve aproximadamente 7 veces más rápidamente que el establecimiento de BindingContext en un enlace clásico.

Estas diferencias de rendimiento se pueden ampliar en dispositivos móviles, dependiendo de la plataforma que se utilice, la versión del sistema operativo que se utilice y el dispositivo en el que se ejecute la aplicación.