DataTemplate

Imagina que tuvieses un control de tipo lista capaz de realizar una representación visual distinta para cada uno de sus controles según el tipo de dato que reciba. Es decir: con pocas líneas de código podremos aplicar diferentes plantillas a múltiples objetos.

Esto puede realizarse con el uso de un DataTemplate de XAML disponible en WPF, UWP… Es bastante simple y, además, obtendremos un código muy limpio y claro. Solo hay que entender su funcionamiento para poder aprovechar al máximo lo que nos ofrece.

Para explicarlo mejor vamos a ver paso por paso un ejemplo de una POC simulando una app sobre viajes personales tipo blog. Está hecho en WPF, pero para las personas que se inicien en Xamarin esto también les valdrá, hay ciertos matices que cambian pero el trasfondo es el mismo. Dejaré todo el código en nuestro GitHub.

Empecemos por el principio

Para entender qué es un DataTemplate primero explicaré el ControlTemplate.

El ControlTemplate es una plantilla encargada de definir la estructura y el comportamiento visual de un control. Puede tener un control decorativo, por ejemplo, un Border; puede tener otro control con funcionalidad, por ejemplo, un menú contextual con diferentes funcionalidades; o simplemente no tener ningún elemento visual ni funcional, ser únicamente una estructura. Es decir, por cada tipo de control que se cree, este tendrá la misma apariencia y el mismo comportamiento definido previamente por el ControlTemplate.

Dentro de ControlTemplate definimos los datos que queremos enlazar con la plantilla. Esto se hará mediante ContentControl o ContentPresenter.

Y llegamos a la esperada plantilla DataTemplate, que definirá el modelo visual según el contexto de datos. Visualmente sería algo parecido al siguiente gráfico:

El código

Models

La aplicación sigue el patrón de diseño MVVM, así que lo primero que haremos será definir los modelos que vamos a utilizar. En mi caso, he creado únicamente tres:

  • Elements
  • ImageDesign : Elements
  • TextDesign : ImageDesign

ViewModel

Ahora creamos una lista que contenga Elements.

View

El siguiente paso será crear un control de tipo lista en la vista, como por ejemplo ListBoxTambién podría haber utilizado otras opciones basadas en el control ItemsControl, además de un ListBox, como pudieran ser el ComboBox o el ListView.

La propiedad ItemsSource será enlazada a la lista creada en ViewModel. Ahora ListBox sabe que va a recibir datos desde ViewModel.

Con ItemsPanelTemplate definiremos el tipo de contenedor donde se mostrarán los controles, en este caso será un WrapPanel.

ViewModel

Comenzamos con la inserción de controles en ListBox, lo haremos a través de objetos instanciados que iremos añadiendo a AddElements(). Pueden añadirse de forma dinámica a través de Json, SQlite… pero para nuestro POC vamos a hacerlo manualmente por medio de Commands, por lo que he creado tres botones.

Sin una plantilla definida,  la representación visual de estos datos será por medio de un TextBlock, debido a que se ejecuta un método básico de Object() llamado ToString() cuyo comportamiento por defecto es el devolver el nombre de la clase. Ahora mismo tendrá el siguiente aspecto:

ResourceDictionary

Vamos a dar forma a nuestros datos. Empezaremos creando un estilo de tipo ListBoxItem con ControlTemplate. Por el momento trataremos a todos los controles por igual, sin hacer distinciones.

Con este estilo vamos a tener una estructura con un ancho y alto fijo, además de un borde gris. No tiene ningún dato enlazado, no lo conoce.

Para que nuestro Template sepa lo que tiene que representar tendremos que añadirle un ContentControl .

¿Qué tenemos ahora? Un borde gris con un objeto que no sabe interpretar. Necesita de una plantilla para poder representar cada control.

Es ahora cuando debemos desarrollar nuestra creatividad y maquetar nuestros controles. Nos crearemos un DataTemplate diferente por cada objeto y estableceremos la propiedad DataType en función de cada tipo de dato a representar:

Ahora mostrará una plantilla diferente según el objeto que reciba. Y el resultado será el siguiente:

Ya ves que ha sido muy fácil y esto nos dará muchas opciones con un código sencillo y limpio.

Como he comentado al principio del post, el código lo tenéis disponible en GitHub.