Plantillas de datos

Browse sample. Examina la muestra

Las plantillas de datos de interfaz de usuario de aplicaciones multiplataforma .NET (.NET MAUI) permiten definir la presentación de los datos en los controles compatibles.

Considere la posibilidad de un elemento CollectionView que muestra una colección de objetos Person. En el ejemplo siguiente se muestra la definición de la clase Person.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Location { get; set; }
}

La clase Person define las propiedades Name, Age y Location, que se pueden establecer al crear un objeto Person. Un control que muestra colecciones, como CollectionView, puede usarse para mostrar objetos Person:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataTemplates"
             x:Class="DataTemplates.WithoutDataTemplatePage">
    <StackLayout>
        <CollectionView>
            <CollectionView.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>
            </CollectionView.ItemsSource>
        </CollectionView>
    </StackLayout>
</ContentPage>

En este ejemplo, los elementos se agregan a CollectionView inicializando su propiedad ItemsSource de una matriz de objetos Person. CollectionView llama a ToString cuando se muestran los objetos de la colección. Pero, como no hay ninguna invalidación de Person.ToString, ToString devuelve el nombre de tipo de cada objeto:

Screenshot of a CollectionView without a data template.

El objeto Person puede invalidar el método ToString para mostrar datos significativos:

public class Person
{
    ...
    public override string ToString ()
    {
        return Name;
    }
}

Como resultado, CollectionView muestra el valor de propiedad Person.Name para cada objeto de la colección:

Screenshot of a CollectionView that overrides the Person.ToString method.

La invalidación de Person.ToString podría devolver una cadena con formato formada por las propiedades Name, Age y Location. Pero este enfoque solo ofrece un control limitado sobre la apariencia de cada elemento de datos. Para obtener más flexibilidad, se puede crear un elemento DataTemplate que defina la apariencia de los datos.

Crear DataTemplate

DataTemplate se usa para especificar la apariencia de los datos, y normalmente se utiliza el enlace de datos para mostrar los datos. Un escenario de uso común para plantillas de datos es mostrar datos de una colección de objetos en un control como CollectionView o CarouselView. Por ejemplo, cuando se enlaza un CollectionView a una colección de objetos Person, la propiedad CollectionView.ItemTemplate puede establecerse en DataTemplate que define la apariencia de cada objeto Person de CollectionView. DataTemplate contendrá los objetos que se enlazan a los valores de propiedad de cada objeto Person. Para obtener más información sobre el enlace de datos, consulta Enlace de datos.

DataTemplate que se define insertado en un control se conoce como una plantilla insertada. Como alternativa, las plantillas de datos se puedes definir como un recurso de nivel de control, de página o de aplicación. La elección de dónde se puede definir un elemento DataTemplate afecta a dónde se puede usar:

  • Una instancia de DataTemplate definida en el nivel de control solo se puede aplicar al control.
  • Un instancia de DataTemplate definida en el nivel de página se puede aplicar a varios controles válidos de la página.
  • Una instancia de DataTemplate definida en el nivel de aplicación se puede aplicar a los controles válidos de la aplicación.

Nota:

Las plantillas de datos situadas más abajo en la jerarquía de vistas tienen prioridad sobre las definidas más arriba cuando comparten atributos x:Key. Por ejemplo, una plantilla de datos de nivel de página invalidará una plantilla de datos de nivel de aplicación, y una plantilla de datos de nivel de página invalidará una plantilla de datos de nivel de control o una plantilla de datos insertada.

DataTemplate se puede crear insertado, con un tipo o como un recurso, sin importar dónde se defina.

Creación de DataTemplate insertado

Una plantilla de datos insertada, que es la que se define insertada en un control, debe usarse si no hay necesidad de reutilizar la plantilla de datos en otro lugar. Los objetos especificados en DataTemplate definen la apariencia de cada elemento de datos. Después, un control como CollectionView puede establecer su propiedad ItemTemplate en el insertado DataTemplate:

<CollectionView>
    <CollectionView.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>
    </CollectionView.ItemsSource>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid>
                ...
                <Label Text="{Binding Name}" FontAttributes="Bold" />
                <Label Grid.Column="1" Text="{Binding Age}" />
                <Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

En CollectionView, el elemento secundario de DataTemplate insertado debe derivar de BindableObject. En este ejemplo, se usa Grid, que deriva de Layout. Grid contiene tres instancias de Label que enlazan sus propiedades Text a las propiedades adecuadas de cada objeto Person de la colección. En la captura de pantalla siguiente se muestra el resultado de la apariencia:

Screenshot of a CollectionView with a data template.

Creación de DataTemplate con un tipo

Se puede crear DataTemplate con un tipo de vista personalizado. La ventaja de este enfoque es que la apariencia definida por la vista se puede reutilizar en varias plantillas de datos de una aplicación. Después un control como CollectionView puede establecer su propiedad ItemTemplate en :DataTemplate

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataTemplates"
             x:Class="DataTemplates.WithDataTemplatePageFromType">
    <StackLayout>
        <CollectionView>
           <CollectionView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </CollectionView.ItemsSource>
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <local:PersonView />
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

En este ejemplo, la propiedad CollectionView.ItemTemplate se establece en DataTemplate que se crea a partir de un tipo personalizado que define la apariencia de la vista. El tipo personalizado debe derivar de ContentView:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataTemplates.PersonView">
     <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>
</ContentView>

En este ejemplo, el diseño dentro de ContentView se administra mediante un objeto Grid. Grid contiene tres instancias de Label que enlazan sus propiedades Text a las propiedades adecuadas de cada objeto Person de la colección.

Para más información sobre cómo crear vistas personalizadas, ve ContentView.

Creación de una plantilla de datos como recurso

Las plantillas de datos también se pueden crear como objetos reutilizables en un elemento ResourceDictionary. Esto se consigue asignando a cada uno un valor DataTemplateúnicox:Key, para darle una clave descriptiva en ResourceDictionary. Después un control como CollectionView puede establecer su propiedad ItemTemplate en :DataTemplate

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataTemplates"
             x:Class="DataTemplates.WithDataTemplateResource">
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="personTemplate">
                <Grid>
                    ...
                </Grid>
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <CollectionView ItemTemplate="{StaticResource personTemplate}">
            <CollectionView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </CollectionView.ItemsSource>
        </CollectionView>
    </StackLayout>
</ContentPage>

En este ejemplo, DataTemplate se asigna a la propiedad CollectionView.ItemTemplate mediante la extensión de marcado StaticResource. Ten 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 nivel de la aplicación.

Creación de un 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 plantillas de datos al mismo tipo de objeto para seleccionar su apariencia de objetos en tiempo de ejecución. Un selector de plantillas de datos habilita escenarios como el enlace CollectionView o CarouselView a una colección de objetos, donde la apariencia de cada objeto se puede elegir en tiempo de ejecución mediante el selector de plantillas de datos devolviendo un elemento DataTemplate específico.

Un selector de plantillas de datos se implementa mediante la creación de una clase que hereda de DataTemplateSelector. A continuación, se debe invalidar el método OnSelectTemplate para devolver un elemento específico DataTemplate:

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;
    }
}

En este ejemplo, el método OnSelectTemplate devuelve una plantilla de datos específica basada en el valor de la propiedad DateOfBirth. La plantilla de datos devuelta se define mediante la propiedad ValidTemplate o InvalidTemplate que se establecen al consumir el selector de plantillas de datos.

Limitaciones

Los objetos DataTemplateSelector tienen las siguientes limitaciones:

  • 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. Si no lo haces, se creará una fuga de memoria y se deshabilitará la virtualización del control.

Consumo de dataTemplateSelector

Un selector de plantillas de datos se puede consumir creando como un recurso y asignando su instancia a las propiedades de control .NET MAUI de tipo DataTemplate, como CollectionView.ItemTemplate.

En el ejemplo siguiente se muestra cómo declarar PersonDataTemplateSelector como un recurso de nivel de página:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:local="clr-namespace:Selector"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Selector.MainPage">
    <ContentPage.Resources>
        <DataTemplate x:Key="validPersonTemplate">
            <Grid>
                ...
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="invalidPersonTemplate">
            <Grid>
                ...
            </Grid>
        </DataTemplate>
        <local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
                                          ValidTemplate="{StaticResource validPersonTemplate}"
                                          InvalidTemplate="{StaticResource invalidPersonTemplate}" />
    </ContentPage.Resources>
    ...
</ContentPage>

En este ejemplo, el nivel de página ResourceDictionary define dos objetos DataTemplate y un objeto PersonDataTemplateSelector. El objeto PersonDataTemplateSelector establece sus propiedades ValidTemplate y InvalidTemplate en los objetos DataTemplate mediante la extensión de marcado StaticResource. Aunque los recursos se definen en ResourceDictionary de la página, también se pueden definir en el nivel de control o nivel de la aplicación.

El objeto PersonDataTemplateSelector se puede consumir asignando la propiedad CollectionView.ItemTemplate:

<CollectionView x:Name="collectionView"
                ItemTemplate="{StaticResource personDataTemplateSelector}" />

En tiempo de ejecución, CollectionView 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, DataTemplate devuelto se aplica a ese objeto.

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

Screenshot of a CollectionView with a data template selector.

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.