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:
- 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.
- 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:
- Habilite la compilación XAML. Para obtener más información acerca de la compilación XAML, consulte XAML Compilation (Compilación XAML).
- Establezca un atributo
x:DataType
de un elementoVisualElement
para el tipo del objeto al cualVisualElement
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:
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 DataTemplate
x:DataType
NamedColor
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
:
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
oTwoWay
) 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 enlaceOneWay
,OneWayToSource
oTwoWay
) se resuelve aproximadamente 5 veces más rápidamente que el establecimiento deBindingContext
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 enlaceOneTime
) se resuelve aproximadamente 7 veces más rápidamente que el establecimiento deBindingContext
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.