[Windows 10] Utilizando x:Bind en un diccionario de recursos

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 10 tenemos la posibilidad de crear bindings compilados en lugar de los bindings clásicos.

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

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, en un diccionario de recursos. Creamos el diccionario de recursos:

Creamos diccionario de recursos

Creamos diccionario de recursos

Lo registramos en los recursos de la App:

<ResourceDictionary.MergedDictionaries>
     <ResourceDictionary Source="/Styles/AppResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>  

Definimos el template:

<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}" />

Ejecutamos la App y…

Error de compilación

Error de compilación

Diccionario de recursos, el problema

x:Bind o bindings compilados, como indicamos en el nombre deben ser precompilados. No podemos añadir recursos haciendo uso de bindings compilados ya sea a nivel de página o de Aplicación directamente; debemos inicializar e instanciar una clase.

La solución

Debemos añadir una clase parcial, código asociado al recurso para poder realizar la instanciación del mismo. Creamos la clase parcial:

public partial class AppResourceDictionary
{
     public AppResourceDictionary()
     {
         InitializeComponent();
     }
}

Asociamos la clase parcial con nuestro diccionario de recursos:

x:Class="XBindResources.Resources.AppResourceDictionary"

Modificamos el diccionario de recursos añadiendo la etiqueta x:Class. A continuación, instanciamos el diccionario de recursos:

<ResourceDictionary.MergedDictionaries>
                
     <!-- Resources -->
     <resources:AppResourceDictionary />      
                
</ResourceDictionary.MergedDictionaries>

Nos aseguramos que se lanza la llamada a InitializeComponent del mismo.

Si ejecutamos ahora nuestra App:

DataTemplate utilizando x:Bind y x:Phase

DataTemplate utilizando x:Bind y x:Phase

Voila!

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

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

Ver GitHub

Más información

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