Creación de una plantilla de datos de Xamarin.Forms

Download SampleDescargar el ejemplo

Las plantillas de datos se pueden crear insertadas, en un objeto ResourceDictionary, o bien a partir de un tipo personalizado o un tipo de celda de Xamarin.Forms adecuado. En este artículo se explora cada una de las técnicas.

Un escenario de uso común para un elemento DataTemplate es mostrar datos de una colección de objetos en un control ListView. La apariencia de los datos de cada celda del control ListView se puede administrar mediante el establecimiento de la propiedad ListView.ItemTemplate en un elemento DataTemplate. Se pueden usar varias técnicas para realizar esta acción:

Independientemente de la técnica que se use, el resultado es que la apariencia de cada celda del control ListView se define mediante un elemento DataTemplate, como se muestra en las capturas de pantalla siguientes:

ListView with a DataTemplate

Creación de una plantilla de datos insertada

La propiedad ListView.ItemTemplate se puede establecer en un elemento DataTemplate insertado. Una plantilla insertada, que es la que se coloca como elemento secundario directo de una propiedad de control adecuada, se debe usar si no hay ninguna necesidad de reutilizar la plantilla de datos en otros puntos. Los elementos especificados en el elemento DataTemplate definen la apariencia de cada celda, como se muestra en el ejemplo de código XAML siguiente:

<ListView Margin="0,20,0,0">
    <ListView.ItemsSource>
        <x:Array Type="{x:Type local:Person}">
            <local:Person Name="Steve" Age="21" Location="USA" />
            <local:Person Name="John" Age="37" Location="USA" />
            <local:Person Name="Tom" Age="42" Location="UK" />
            <local:Person Name="Lucas" Age="29" Location="Germany" />
            <local:Person Name="Tariq" Age="39" Location="UK" />
            <local:Person Name="Jane" Age="30" Location="USA" />
        </x:Array>
    </ListView.ItemsSource>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    ...
                    <Label Text="{Binding Name}" FontAttributes="Bold" />
                    <Label Grid.Column="1" Text="{Binding Age}" />
                    <Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

El elemento secundario de un elemento DataTemplate insertado debe ser de tipo Cell, o bien derivarse de él. En este ejemplo se usa un ViewCell, que procede de Cell. Aquí, el diseño dentro de ViewCell se administra mediante un control Grid. Grid contiene tres instancias de Label que enlazan sus propiedades Text a las propiedades adecuadas de cada objeto Person de la colección.

El código de C# equivalente se muestra en el ejemplo de código siguiente:

public class WithDataTemplatePageCS : ContentPage
{
    public WithDataTemplatePageCS()
    {
        ...
        var people = new List<Person>
        {
            new Person { Name = "Steve", Age = 21, Location = "USA" },
            ...
        };

        var personDataTemplate = new DataTemplate(() =>
        {
            var grid = new Grid();
            ...
            var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
            var ageLabel = new Label();
            var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

            nameLabel.SetBinding(Label.TextProperty, "Name");
            ageLabel.SetBinding(Label.TextProperty, "Age");
            locationLabel.SetBinding(Label.TextProperty, "Location");

            grid.Children.Add(nameLabel);
            grid.Children.Add(ageLabel, 1, 0);
            grid.Children.Add(locationLabel, 2, 0);

            return new ViewCell { View = grid };
        });

        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = {
                ...
                new ListView { ItemsSource = people, ItemTemplate = personDataTemplate, Margin = new Thickness(0, 20, 0, 0) }
            }
        };
    }
}

En C#, el elemento DataTemplate insertado se crea mediante una sobrecarga del constructor que especifica un argumento Func.

Creación de una plantilla de datos con un tipo

La propiedad ListView.ItemTemplate también se puede establecer en un elemento DataTemplate creado a partir de un tipo de celda. La ventaja de este enfoque es que la apariencia definida por el tipo de celda se puede reutilizar en varias plantillas de datos en toda la aplicación. En el código XAML siguiente se muestra un ejemplo de este enfoque:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataTemplates"
             ...>
    <StackLayout Margin="20">
        ...
        <ListView Margin="0,20,0,0">
           <ListView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <local:PersonCell />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

En este caso, la propiedad ListView.ItemTemplate se establece en un elemento DataTemplate creado a partir de un tipo personalizado que define el aspecto de la celda. El tipo personalizado se debe derivar del tipo ViewCell, como se muestra en el ejemplo de código siguiente:

<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="DataTemplates.PersonCell">
     <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.2*" />
            <ColumnDefinition Width="0.3*" />
        </Grid.ColumnDefinitions>
        <Label Text="{Binding Name}" FontAttributes="Bold" />
        <Label Grid.Column="1" Text="{Binding Age}" />
        <Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
    </Grid>
</ViewCell>

Dentro de ViewCell, el diseño se administra mediante un control Grid. Grid contiene tres instancias de Label que enlazan sus propiedades Text a las propiedades adecuadas de cada objeto Person de la colección.

El código de C# equivalente se muestra en el ejemplo siguiente:

public class WithDataTemplatePageFromTypeCS : ContentPage
{
    public WithDataTemplatePageFromTypeCS()
    {
        ...
        var people = new List<Person>
        {
            new Person { Name = "Steve", Age = 21, Location = "USA" },
            ...
        };

        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = {
                ...
                new ListView { ItemTemplate = new DataTemplate(typeof(PersonCellCS)), ItemsSource = people, Margin = new Thickness(0, 20, 0, 0) }
            }
        };
    }
}

En C#, DataTemplate se crea mediante una sobrecarga del constructor que especifica el tipo de celda como argumento. El tipo de celda se debe derivar del tipo ViewCell, como se muestra en el ejemplo de código siguiente:

public class PersonCellCS : ViewCell
{
    public PersonCellCS()
    {
        var grid = new Grid();
        ...
        var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
        var ageLabel = new Label();
        var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

        nameLabel.SetBinding(Label.TextProperty, "Name");
        ageLabel.SetBinding(Label.TextProperty, "Age");
        locationLabel.SetBinding(Label.TextProperty, "Location");

        grid.Children.Add(nameLabel);
        grid.Children.Add(ageLabel, 1, 0);
        grid.Children.Add(locationLabel, 2, 0);

        View = grid;
    }
}

Nota:

Tenga en cuenta que Xamarin.Forms también incluye tipos de celda que se pueden usar para mostrar datos simples en celdas ListView. Para obtener más información, vea Apariencia de una celda.

Creación de una plantilla de datos con un recurso

Las plantillas de datos también se pueden crear como objetos reutilizables en un objeto ResourceDictionary. Esto se consigue mediante la asignación de un atributo x:Key único a cada declaración, para proporcionarle una clave descriptiva en el objeto ResourceDictionary, como se muestra en el ejemplo de código XAML siguiente:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             ...>
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="personTemplate">
                 <ViewCell>
                    <Grid>
                        ...
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Margin="20">
        ...
        <ListView ItemTemplate="{StaticResource personTemplate}" Margin="0,20,0,0">
            <ListView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </ListView.ItemsSource>
        </ListView>
    </StackLayout>
</ContentPage>

El elemento DataTemplate se asigna a la propiedad ListView.ItemTemplate mediante la extensión de marcado StaticResource. Tenga en cuenta que aunque el elemento DataTemplate se defina en el objeto ResourceDictionary de la página, también se puede definir en el nivel de control o aplicación.

En el ejemplo de código siguiente se muestra la página equivalente en C#:

public class WithDataTemplatePageCS : ContentPage
{
  public WithDataTemplatePageCS ()
  {
    ...
    var personDataTemplate = new DataTemplate (() => {
      var grid = new Grid ();
      ...
      return new ViewCell { View = grid };
    });

    Resources = new ResourceDictionary ();
    Resources.Add ("personTemplate", personDataTemplate);

    Content = new StackLayout {
      Margin = new Thickness(20),
      Children = {
        ...
        new ListView { ItemTemplate = (DataTemplate)Resources ["personTemplate"], ItemsSource = people };
      }
    };
  }
}

El elemento DataTemplate se agrega a ResourceDictionary con el método Add, que especifica una cadena Key que se usa para hacer referencia al elemento DataTemplate al recuperarlo.

Resumen

En este artículo se ha explicado cómo crear plantillas de datos, insertadas, a partir de un tipo personalizado, o bien en un objeto ResourceDictionary. Una plantilla insertada se debe usar si no es necesario volver a utilizarla en otro lugar. Como alternativa, se puede reutilizar una plantilla de datos si se define como un tipo personalizado, o como un recurso de nivel de página o el nivel de aplicación de nivel de control.