[Windows 10] x:Bind, bindings compilados

Link - 05Introducción

Data binding es un mecanismo mediante el cual podemos enlazar los elementos de la interfaz de usuario con los objetos que contienen la información a mostrar. Cuando realizamos data binding, creamos una dependencia entre el valor de una propiedad llamada target con el valor de otra propiedad llamada source. Donde normalmente, la propiedad target recibirá el valor de la propiedad source.

Es el mecanismo base que nos permite utilizar el patrón MVVM en nuestras Apps móviles logrando:

  • Nos permite dividir el trabajo de manera muy sencilla (diseñadores – desarrolladores)
  • El mantenimiento es más sencillo.
  • Permite realizar Test a nuestro código.
  • Permite una más fácil reutilización de código.

Sin embargo, además de toda la potencia mencionada teníamos ciertas limitaciones. Los errores de Binding no se producían en tiempo de compilación de la App además de tener diferentes mejoras relacionadas con el rendimiento. Limitaciones existentes hasta ahora…

Con la llegada de Windows 1o tenemos la posibilidad de crear bindings compilados en lugar de los bindings clásicos.

¿Cómo se usan?, ¿que aportan?, ¿cúando usarlos?

A todas esas preguntas daremos respuesta en este artículo.

x:Bind

x:Bind es una nueva síntaxis en XAML que cubre un objetivo similar a Binding. Permite crear un enlace a datos pero con significativas diferencias. Mientras que con Binding se utiliza reflexión en tiempo de ejecución para resolver el enlace a datos, con x:Bind se realiza una validación en tiempo de ejecución ya que son fuertemente tipados y compilados. Además, ofrece potentes mejoras en el rendimiento.

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

Nuestro objetivo en este primer ejemplo será crear 1600 Borders bindeados a colores utilizando Bindings clásicos y Bindings compilados. De esta forma podremos realizar una interesante comparativa en los tiempos necesarios por cada forma para realizar el enlace a datos así como otros detalles interesantes como el consumo de memoria, etc.

Comenzamos creando un diccionario de recursos donde definiremos los distintos colores:

<SolidColorBrush x:Key="BackgroundA" Color="Red" />
<SolidColorBrush x:Key="BackgroundB" Color="Blue" />
<SolidColorBrush x:Key="BackgroundC" Color="Green" />
<SolidColorBrush x:Key="BackgroundD" Color="Yellow" />

A continuación crearemos dos vistas nuevas. En una de ellas crearemos cientos de Borders utilizando enlace de datos clásico:

<Border Height="30" Width="30" Background="{Binding BackgroundA}" />
<Border Height="30" Width="30" Background="{Binding BackgroundB}" />
<Border Height="30" Width="30" Background="{Binding BackgroundC}" />
<Border Height="30" Width="30" Background="{Binding BackgroundD}" />

Mientras que en la otra utilizaremos x:Bind:

<Border Height="30" Width="30" Background="{x:Bind BackgroundA}" />
<Border Height="30" Width="30" Background="{x:Bind BackgroundB}" />
<Border Height="30" Width="30" Background="{x:Bind BackgroundC}" />
<Border Height="30" Width="30" Background="{x:Bind BackgroundD}" />

Para utilizar bindings compilados reemplazaremos {Binding} por {x:Bind}. Los bindings compilados están fuertemente tipados por lo que es necesario indicar el tipo del contexto siendo por defecto la página o el control personal en si.

NOTA: El modo de binding utilizado por defecto en bindings compilados es OneTime.

En la vista principal tendremos un par de botones que nos permitan instanciar y medir el tiempo necesario para ello en cada caso:

var date = DateTime.Now;
var binding = new XBind();
string diff = string.Empty;
binding.Loaded += (s, args) =>
{
     diff = (DateTime.Now - date).ToString();
     Diff.Text = diff;
};

Content.Children.Add(binding);

Si ejecutamos la App y pulsamos el botón “Binding”:

Bindings clásicos

Bindings clásicos

Si utilizamos x:Bind:

x:Bind

x:Bind

Si comparamos los tiempos vemos que… se reduce a practicamente la mitad!

Además, analizando consumo de memoria y CPU vemos la siguiente comparativa.

Uso de CPU utilizando enlace a datos clásico:

Uso de CPU en Bindings clásicos

Uso de CPU en Bindings clásicos

Uso de CPU utilizando bindings compilados:

Uso de CPU en binding compilado

Uso de CPU en binding compilado

También se reduce el consumo de memoria en comparación con Bindings clásicos:

Comparativa de consumo de memoria entre Bindings

Comparativa de consumo de memoria entre Bindings

Podéis descargar el ejemplo realizado a continuación:

También podéis acceder al código fuente directamente en GitHub:

Ver GitHubUtilizando x:Bind

Vista las visibles mejoras a nivel de rendimiento, vamos a crear una App “normal” donde veamos su uso.

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

En esta ocasión, nuestro objetivo sera crear un listado de casas donde utilizaremos x:Bind en la plantilla que representará cada elemento de la lista.

Comenzamos creando la entidad casa dentro de la carpeta Models:

public class House
{
     public string Place { get; set; }
     public string Price { get; set; }
     public string Photo { get; set; }
}

Nuestra interfaz sera muy simple en esta ocasión contando con un sencillo ListView:

<ListView
     ItemsSource="{Binding Houses}" />

El control tiene la fuente de datos enlazada a una propiedad de la ViewModel:

private ObservableCollection<House> _houses; 

public ObservableCollection<House> Houses
{
     get
     {
          if (_houses == null)
               LoadHouses();

          return _houses;
     }
} 

Cargaremos el listado de casas con un método creando datos falsos en local de manera aleatoria:

private void LoadHouses()
{
     _houses = new ObservableCollection<House>();
     Random random = new Random();
     for (int i = 0; i < 100; i++)
     {
          _houses.Add(new House
          {
               Place = Places[random.Next(0, Places.Count)],
               Photo = string.Format("ms-appx:///Assets/{0}.png", random.Next(1, 4)),
               Price = string.Format("${0}", random.Next(10000, 100000).ToString())
          });
     }
}

Y llegamos a la parte más importante, la definición del template de cada casa:

<DataTemplate x:Key="HouseTemplate" x:DataType="model:House">
     <Grid Width="200"
           Height="80">
          <Grid.ColumnDefinitions>
               <ColumnDefinition Width="75" />
               <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
               <RowDefinition Height="Auto" />
               <RowDefinition Height="Auto" />
           </Grid.RowDefinitions>
           <Image Grid.RowSpan="2"
              Source="{x:Bind Photo}"
              MaxWidth="70"
              MaxHeight="70" />
           <TextBlock Text="{x:Bind Place}"    
                  Grid.Column="1"
                  FontSize="18"/>
           <TextBlock Text="{x:Bind Price}"  
                  Grid.Column="1"  
                  Grid.Row="1"
                  FontSize="12" />
     </Grid>
</DataTemplate>

Utilizamos x:Bind para enlazar cada elemento visual de la plantilla a la propiedad deseada. Importante resaltar además de compilados, son fuertemente tipados. Es obligatorio para no tener errores de compilación indicar el tipo de los datos a los que accedemos por enlace a datos. Esto lo realizamos utilizando x:DataType. En nuestro ejemplo, la entidad House.

Nuestro ListView quedara:

<ListView
     ItemsSource="{Binding Houses}"
     ItemTemplate="{StaticResource HouseTemplate}" />

Ejecutando la App:

DataTemplate utilizando x:Bind

DataTemplate utilizando x:Bind

Podéis descargar el ejemplo realizado a continuación:

También podéis acceder al código fuente directamente en GitHub:

Ver GitHub

¿Cuándo utilizar Bindings compilados?

Lo visto hasta ahora nos indica que:

  • Tenemos la posibilidad de tener bindings compilados obteniendo errores en tiempo de compilación.
  • Son fuertemente tipados por lo que debemos indicar el tipo de la información.
  • Obtenemos mejoras en el rendimiento tanto en consumo de CPU como de memoria.

Por lo tanto, ¿lo usamos siempre?

La respuesta corta es no. Entrando en profundidad:

  • Los bindings compilados, en ocasiones,  tienen un comportamiento diferente al de los bindings clásicos existiendo situaciones no válidas para los primeros.
  • Los bindings compilados como indicamos al nombrarlos se compilan permitiéndonos obtener errores en tiempo de compilación pero tambien nos aporta limitaciones. No podemos crear bindings compilados dinámicamente (añadir o quitar bindings en runtime).
  • Con los bindings clásicos podemos crear un mismo template para entidades diferentes siempre y cuando el nombre de las propiedades coincida. Con los bindings compilados como hemos visto, estan fuertemente tipados y no podemos realizar lo mismo.

Por lo tanto, en nuestros desarrollos entran en juego los bindings compilados pero no sustituyen en abosluto a los bindings clásicos. Dependiendo de la situación utilizaremos unos u otros en consecuencia.

Más información

3 pensamientos en “[Windows 10] x:Bind, bindings compilados

  1. Pingback: [Windows 10 Anniversary Update] Novedades en x:Bind, bindings compilados | Javier Suárez | Blog

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s