Criando um Xamarin.Forms DataTemplate
Os modelos de dados podem ser criados embutidos, em um ResourceDictionary ou de um tipo personalizado ou tipo de célula apropriado Xamarin.Forms . Este artigo explora cada técnica.
Um cenário de uso comum para um DataTemplate
é exibir dados de uma coleção de objetos em um ListView
. A aparência dos dados para cada célula no ListView
pode ser gerenciada definindo a propriedade ListView.ItemTemplate
como um DataTemplate
. Há várias técnicas que podem ser usadas para fazer isso:
- Criando um DataTemplate embutido.
- Criando um DataTemplate com um tipo.
- Criando um DataTemplate como um recurso.
Independentemente da técnica que está sendo usada, o resultado é que a aparência de cada célula no ListView
é definida por um DataTemplate
, conforme mostrado nas seguintes capturas de tela:
Criando um DataTemplate embutido
A propriedade ListView.ItemTemplate
pode ser definida como um DataTemplate
embutido. Um modelo embutido, que é inserido como um filho direto de uma propriedade de controle apropriada, deverá ser usado se não houver necessidade de reutilizar o modelo de dados em outro lugar. Os elementos especificados no DataTemplate
definem a aparência de cada célula, conforme mostrado no exemplo de código XAML a seguir:
<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>
O filho de um DataTemplate
embutido deve ser do tipo Cell
ou derivado dele. Este exemplo usa um ViewCell
, que deriva de Cell
. O layout dentro do ViewCell
é gerenciado aqui por um Grid
. O Grid
contém três instâncias Label
que associam suas propriedades Text
às propriedades adequadas de cada objeto Person
na coleção.
O código C# equivalente é mostrado no exemplo de código a seguir:
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) }
}
};
}
}
Em C#, o DataTemplate
embutido é criado usando uma sobrecarga de construtor que especifica um argumento Func
.
Criando um DataTemplate com um tipo
A propriedade ListView.ItemTemplate
também pode ser definida como uma DataTemplate
criada com base em um tipo de célula. A vantagem dessa abordagem é que a aparência definida pelo tipo de célula pode ser reutilizado por vários modelos de dados em todo o aplicativo. O código XAML a seguir mostra um exemplo dessa abordagem:
<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>
Aqui, a propriedade ListView.ItemTemplate
é definida como um DataTemplate
criado com base em um tipo personalizado que define a aparência da célula. O tipo personalizado deve ser derivado do tipo ViewCell
, conforme mostrado no exemplo de código a seguir:
<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 do ViewCell
, o layout é gerenciado aqui por um Grid
. O Grid
contém três instâncias Label
que associam suas propriedades Text
às propriedades adequadas de cada objeto Person
na coleção.
O código C# equivalente é mostrado no exemplo a seguir:
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) }
}
};
}
}
Em C#, o DataTemplate
é criado usando uma sobrecarga de construtor que especifica o tipo de célula como um argumento. O tipo de célula deve ser derivado do tipo ViewCell
, conforme mostrado no exemplo de código a seguir:
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;
}
}
Observação
Observe que Xamarin.Forms também inclui tipos de células que podem ser usados para exibir dados simples em ListView
células. Para saber mais, confira Cell Appearance (Aparência da célula).
Criando um DataTemplate como um recurso
Os modelos de dados também podem ser criados como objetos reutilizáveis em um ResourceDictionary
. Isso é feito dando a cada declaração um atributo x:Key
exclusivo, que fornece a ela uma chave descritiva no ResourceDictionary
, conforme mostrado no exemplo de código XAML a seguir:
<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>
O DataTemplate
é atribuído à propriedade ListView.ItemTemplate
usando a extensão de marcação StaticResource
. Observe que, embora o DataTemplate
seja definido no ResourceDictionary
da página, ele também poderia ser definido no nível do controle ou do aplicativo.
O exemplo de código a seguir mostra a página equivalente em 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 };
}
};
}
}
O DataTemplate
é adicionado ao ResourceDictionary
usando o método Add
, que especifica uma cadeia de caracteres Key
usada para referenciar o DataTemplate
ao recuperá-la.
Resumo
Este artigo explicou como criar modelos de dados, embutidos, com base em um tipo personalizado ou em um ResourceDictionary
. Um modelo embutido deve ser usado caso não haja necessidade de reutilizar o modelo de dados em outro lugar. Como alternativa, um modelo de dados pode ser reutilizado, definindo-o como um tipo personalizado ou como um recurso de aplicativo de nível de controle, de página ou de aplicativo.