Creación de DataTemplateSelector de Xamarin.Forms

Un elemento DataTemplateSelector se puede usar para elegir una plantilla de datos en tiempo de ejecución según el valor de una propiedad enlazada a datos. Esto permite aplicar varias instancias de DataTemplate al mismo tipo de objeto, para personalizar la apariencia de objetos concretos. En este artículo se explica cómo crear y consumir una instancia de DataTemplateSelector.

Un selector de plantillas de datos habilita escenarios como el enlace de ListView a una colección de objetos, donde la apariencia de cada objeto de ListView se puede elegir en tiempo de ejecución mediante el selector de plantillas de datos devolviendo un elemento DataTemplate determinado.

Creación de DataTemplateSelector de

Un selector de plantillas de datos se implementa mediante la creación de una clase que hereda de DataTemplateSelector. Después, se reemplaza el método OnSelectTemplate para devolver un elemento DataTemplate, como se muestra en el ejemplo de código siguiente:

public class PersonDataTemplateSelector : DataTemplateSelector
{
  public DataTemplate ValidTemplate { get; set; }
  public DataTemplate InvalidTemplate { get; set; }

  protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
  {
    return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
  }
}

El método OnSelectTemplate devuelve la plantilla adecuada en función del valor de la propiedad DateOfBirth. La plantilla que se devuelve es el valor de las propiedades ValidTemplate o InvalidTemplate, que se establecen cuando se consume PersonDataTemplateSelector.

Después, se puede asignar una instancia de la clase de selector de plantilla de datos a propiedades de control de Xamarin.Forms, como ListView.ItemTemplate. Para obtener una lista de las propiedades válidas, vea Creación de una plantilla de datos.

Limitaciones

Las instancias de DataTemplateSelector tienen las limitaciones siguientes:

  • La subclase DataTemplateSelector siempre debe devolver la misma plantilla para los mismos datos si se consultan varias veces.
  • La subclase DataTemplateSelector no debe devolver otra subclase DataTemplateSelector.
  • La subclase DataTemplateSelector no debe devolver nuevas instancias de DataTemplate en cada llamada. En su lugar, se debe devolver la misma instancia. De lo contrario, se creará una fuga de memoria y se deshabilitará la virtualización.
  • En Android, no puede haber más de 20 plantillas de datos diferentes por ListView.

Consumo de una instancia de DataTemplateSelector en XAML

En XAML, se pueden crear instancias de PersonDataTemplateSelector si se declara como un recurso, como se muestra en el ejemplo de código siguiente:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Selector;assembly=Selector" x:Class="Selector.HomePage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="validPersonTemplate">
                <ViewCell>
                   ...
                </ViewCell>
            </DataTemplate>
            <DataTemplate x:Key="invalidPersonTemplate">
                <ViewCell>
                   ...
                </ViewCell>
            </DataTemplate>
            <local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
                ValidTemplate="{StaticResource validPersonTemplate}"
                InvalidTemplate="{StaticResource invalidPersonTemplate}" />
        </ResourceDictionary>
    </ContentPage.Resources>
  ...
</ContentPage>

Este objeto ResourceDictionary de nivel de página define dos instancias de DataTemplate y una instancia de PersonDataTemplateSelector. La instancia de PersonDataTemplateSelector establece sus propiedades ValidTemplate y InvalidTemplate en las instancias de DataTemplate correspondientes mediante la extensión de marcado StaticResource. Tenga en cuenta que aunque los recursos se definen en el objeto ResourceDictionary de la página, también se pueden definir en el nivel de control o aplicación.

La instancia de PersonDataTemplateSelector se consume asignándola a la propiedad ListView.ItemTemplate, como se muestra en el ejemplo de código siguiente:

<ListView x:Name="listView" ItemTemplate="{StaticResource personDataTemplateSelector}" />

En tiempo de ejecución, ListView llama al método PersonDataTemplateSelector.OnSelectTemplate para cada uno de los elementos de la colección subyacente, y la llamada pasa el objeto de datos como el parámetro item. Después, el elemento DataTemplate devuelto por el método se aplica a ese objeto.

En las capturas de pantalla siguientes se muestra el resultado de la aplicación de PersonDataTemplateSelector por parte de ListView a cada objeto de la colección subyacente:

Objeto ListView con un selector de plantillas de datos

Cualquier objeto Person que tenga un valor de propiedad DateOfBirth mayor o igual a 1980 se muestra en color verde, y los demás objetos se muestran en color rojo.

Consumo de una instancia de DataTemplateSelector en C#

En C#, se pueden crear instancias de PersonDataTemplateSelector y asignarlas a la propiedad ListView.ItemTemplate, como se muestra en el ejemplo de código siguiente:

public class HomePageCS : ContentPage
{
  DataTemplate validTemplate;
  DataTemplate invalidTemplate;

  public HomePageCS ()
  {
    ...
    SetupDataTemplates ();
    var listView = new ListView {
      ItemsSource = people,
      ItemTemplate = new PersonDataTemplateSelector {
        ValidTemplate = validTemplate,
        InvalidTemplate = invalidTemplate }
    };

    Content = new StackLayout {
      Margin = new Thickness (20),
      Children = {
        ...
        listView
      }
    };
  }
  ...  
}

La instancia de PersonDataTemplateSelector establece sus propiedades ValidTemplate y InvalidTemplate en las instancias de DataTemplate correspondientes creadas por el método SetupDataTemplates. En tiempo de ejecución, ListView llama al método PersonDataTemplateSelector.OnSelectTemplate para cada uno de los elementos de la colección subyacente, y la llamada pasa el objeto de datos como el parámetro item. Después, el elemento DataTemplate devuelto por el método se aplica a ese objeto.

Resumen

En este artículo se ha explicado cómo crear y consumir un elemento DataTemplateSelector. DataTemplateSelector se puede usar para elegir un elemento DataTemplate en tiempo de ejecución según el valor de una propiedad enlazada a datos. Esto permite aplicar varias instancias de DataTemplate al mismo tipo de objeto para personalizar la apariencia de objetos concretos.