Uso de varios diseños de celda en un elemento ListView

Completado

La capacidad para definir un diseño de celda personalizado proporciona mucho poder para controlar la experiencia del usuario. Pero si las diferentes filas representan diferentes tipos de elementos, nos conviene tener plantillas de celda distintas para cada uno de esos tipos.

Considere la posibilidad de tener nuestra aplicación doméstica inteligente con un elemento ListView de dispositivos inteligentes. Si pensamos en el diseño ideal para una fila de videoportero y para una fila de termostato, es muy probable que sean diferentes.

En esta unidad, vamos a usar DataTemplateSelector para mostrar plantillas de celda diferentes en nuestro elemento ListView.

¿Qué es un DataTemplateSelector?

Podemos usar DataTemplateSelector con el fin de elegir un valor DataTemplate para cada elemento de la colección de origen. Dado que DataTemplate define el tipo de celda que se usará, con el uso de plantillas diferentes la celda se cambia.

Recuerde que, en caso de que todas las filas son iguales, si usamos un elemento ViewCell o algo más sencillo, como un elemento TextCell, necesitamos seguir los pasos siguientes:

  1. Crear un control DataTemplate.
  2. Indicar el valor DataTemplate que va a usar el tipo de celda.
  3. Asignar el valor DataTemplate a la propiedad ListView.ItemTemplate.

Al hacer esto en XAML queda limpio e incluso puede que no parezcan tres pasos independientes:

...
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
...

Pero si queremos que nuestras filas sean capaces de usar diferentes diseños, nuestra propiedad ListView.ItemTemplate se establecerá en un valor DataTemplateSelector personalizado ListView.ItemTemplateDataTemplate. Después, el elemento ListView le preguntará al selector qué DataTemplate se usará para cada fila.

Creación de un DataTemplateSelector

Para crear el selector, tenemos que agregar una clase que se derive de DataTemplateSelector e invalide el método OnSelectTemplate:

class SmartDeviceSelector : Xamarin.Forms.DataTemplateSelector
{
    protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
    {
        ...
    }
}

El elemento de colección enlazado a datos (por ejemplo, el videoportero o el termostato), se pasa a OnSelectTemplate como el parámetro item. A menudo, se va a usar la lógica de bifurcación sencilla para devolver el valor DataTemplate correcto:

...
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
    if (item is doorbell)
        return DoorbellTemplate;
    else
        return GenericTemplate;
}
...

En el código anterior, no se crean instancias de o GenericTemplate. Por motivos de rendimiento, se volverán a usar las mismas instancias de plantilla. Por lo general, las instancias de plantilla se pueden crear como parte del constructor del selector. Se necesita una instancia de plantilla por cada tipo de celda.

Por motivos de rendimiento parecidos, siempre se podrá volver a usar la propia instancia de selector. Cuando se usa XAML, esto se puede hacer más fácilmente si se crea en ResourceDictionary y se hace referencia como un elemento StaticResource:

<ContentPage.Resources>
    <ResourceDictionary>
        <local:CharacterSelector x:Key="SmartDeviceSelector"/>
    </ResourceDictionary>
</ContentPage.Resources>
 
<ListView x:Name="listMessages"
          ItemTemplate="{StaticResource SmartDeviceSelector}"
          ItemsSource="{Binding ChatHistory}"
          HasUnevenRows="True"
          ... />

Comprobar los conocimientos

1.

¿Qué se puede hacer con un elemento DataTemplateSelector?

2.

¿Cuántas instancias de DataTemplate debe crear un valor DataTemplateSelector?