Creazione di un Xamarin.Forms datatemplate

I modelli di dati possono essere creati inline, in un ResourceDictionary o da un tipo personalizzato o da un tipo di cella appropriato Xamarin.Forms . Questo articolo esamina ogni tecnica.

Uno scenario di utilizzo comune per un DataTemplate è la visualizzazione di dati da una raccolta di oggetti in un elemento ListView. L'aspetto dei dati per ogni cella dell'elemento ListView può essere gestito mediante l'impostazione della proprietà ListView.ItemTemplate su un DataTemplate. Esistono diverse tecniche utilizzabili per eseguire questa operazione:

Indipendentemente dalla tecnica che viene utilizzata, il risultato è che l'aspetto di ogni cella dell'elemento ListView è definito da un DataTemplate, come illustrato negli screenshot seguenti:

ListView con un DataTemplate

Creazione di un DataTemplate inline

La proprietà ListView.ItemTemplate può essere impostata su un DataTemplate inline. Usare un modello inline, ovvero un modello inserito come elemento figlio diretto di una proprietà di controllo appropriato, se non è necessario riutilizzare il modello di dati in un'altra posizione. Gli elementi specificati nel DataTemplate definiscono l'aspetto di ogni cella, come illustrato nell'esempio di codice XAML seguente:

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

L'elemento figlio di un DataTemplate inline deve essere di tipo Cell o derivare da questo tipo. Questo esempio usa un elemento ViewCell, che deriva da Cell. Il layout all'interno dell'elemento ViewCell è gestito in questo caso da un elemento Grid. L'elemento Grid contiene tre istanze di Label che associano le loro proprietà Text alle proprietà appropriate di ogni oggetto Person della raccolta.

Il codice C# equivalente è visualizzato nell'esempio seguente:

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

In C# il DataTemplate inline viene creato utilizzando un overload del costruttore che specifica un argomento Func.

Creazione di un DataTemplate con un tipo

La proprietà ListView.ItemTemplate può anche essere impostata su un DataTemplate creato da un tipo di cella. Il vantaggio di questo approccio è che l'aspetto definito dal tipo di cella può essere riutilizzato da più modelli di dati in tutta l'applicazione. Nel codice XAML seguente viene illustrato un esempio di questo approccio:

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

In questo caso, la proprietà ListView.ItemTemplate è impostata su un DataTemplate creato da un tipo personalizzato che definisce l'aspetto delle celle. Il tipo personalizzato deve derivare dal tipo ViewCell, come illustrato nell'esempio di codice seguente:

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

Il layout all'interno dell'elemento ViewCell è gestito in questo caso da un elemento Grid. L'elemento Grid contiene tre istanze di Label che associano le loro proprietà Text alle proprietà appropriate di ogni oggetto Person della raccolta.

Il codice C# equivalente è visualizzato nell'esempio seguente:

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

In C# il DataTemplate viene creato utilizzando un overload del costruttore che specifica il tipo di cella sotto forma di argomento. Il tipo di cella deve derivare dal tipo ViewCell, come illustrato nell'esempio di codice seguente:

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

Si noti che Xamarin.Forms include anche i tipi di cella che possono essere usati per visualizzare dati semplici nelle ListView celle. Per altre informazioni, vedere Customizing ListView Cell Appearance (Personalizzazione dell'aspetto delle celle ListView).

Creazione di un DataTemplate come risorsa

I modelli di dati possono essere creati anche come oggetti riutilizzabili in un elemento ResourceDictionary. Tale risultato si ottiene assegnando a ogni dichiarazione un valore univoco dell'attributo x:Key, che fornisce una chiave descrittiva nell'elemento ResourceDictionary, come illustrato nell'esempio di codice XAML seguente:

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

L'elemento DataTemplate viene assegnato alla proprietà ListView.ItemTemplate usando l'estensione di markup StaticResource. Si noti che anche se il DataTemplate è definito nell'elemento ResourceDictionary della pagina, è possibile definirlo anche a livello di controllo o di applicazione.

L'esempio di codice seguente illustra la pagina equivalente in 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 };
      }
    };
  }
}

Il DataTemplate viene aggiunto all'elemento ResourceDictionary tramite il metodo Add, che specifica una stringa Key usata per creare un riferimento al DataTemplate quando viene recuperato.

Riepilogo

Questo articolo ha descritto come creare modelli di dati inline da un tipo personalizzato o in un elemento ResourceDictionary. Usare un modello inline se non è necessario usare di nuovo il modello di dati altrove. In alternativa, è possibile riusare un modello di dati definendolo come tipo personalizzato o come risorsa a livello di controllo, a livello di pagina o a livello di applicazione.