Layouts vinculáveis em Xamarin.Forms
Os layouts vinculáveis permitem que qualquer classe de layout derivada da Layout<T>
classe gere seu conteúdo vinculando-se a uma coleção de itens, com a opção de definir a aparência de cada item com um DataTemplate
. Layouts associáveis são fornecidos pela classe BindableLayout
, que expõe as seguintes propriedades anexadas:
ItemsSource
– especifica a coleção de itensIEnumerable
a serem exibidos pelo layout.ItemTemplate
– especifica oDataTemplate
a ser aplicado a cada item na coleção de itens exibidos pelo layout.ItemTemplateSelector
– especifica oDataTemplateSelector
que será usado para escolher umDataTemplate
para um item em tempo de execução.
Observação
A propriedade ItemTemplate
tem precedência quando as propriedades ItemTemplate
e ItemTemplateSelector
estão definidas.
Além disso, a classe BindableLayout
expõe as seguintes propriedades associáveis:
EmptyView
– especifica ostring
ou a exibição que será visualizada quando a propriedadeItemsSource
fornull
ou quando a coleção especificada pela propriedadeItemsSource
fornull
ou vazia. O valor padrão énull
.EmptyViewTemplate
– especifica oDataTemplate
que será exibido quando a propriedadeItemsSource
fornull
ou quando a coleção especificada pela propriedadeItemsSource
fornull
ou vazia. O valor padrão énull
.
Observação
A propriedade EmptyViewTemplate
tem precedência quando as propriedades EmptyView
e EmptyViewTemplate
estão definidas.
Todas essas propriedades podem ser anexadas às AbsoluteLayout
classes , FlexLayout
, Grid
, RelativeLayout
, e StackLayout
, que derivam da Layout<T>
classe.
A Layout<T>
classe expõe uma Children
coleção, à qual os elementos filho de um layout são adicionados. Quando a propriedade é definida como uma coleção de itens e anexada BindableLayout.ItemsSource
a uma Layout<T>
classe derivada, cada item da coleção é adicionado à Layout<T>.Children
coleção para exibição pelo layout. A classe derivada do Layout<T>
atualizará suas exibições filho quando a coleção subjacente for alterada. Para obter mais informações sobre o ciclo de Xamarin.Forms layout, consulte Criando um layout personalizado.
Os layouts associáveis só devem ser usados quando a coleção de itens a serem exibidos for pequena, e a rolagem e a seleção não são necessárias. Embora a rolagem possa ser fornecida encapsulando um layout associável em um ScrollView
, isso não é recomendado, pois os layouts associáveis não têm virtualização da interface do usuário. Quando a rolagem é necessária, um modo de exibição rolável que inclui a virtualização da interface do usuário, como ListView
ou CollectionView
, deve ser usado. Não observar essa recomendação pode levar a problemas de desempenho.
Importante
Embora seja tecnicamente possível anexar um layout associável a qualquer classe de layout derivada da Layout<T>
classe, nem sempre é prático fazer isso, especialmente para as AbsoluteLayout
classes , Grid
e RelativeLayout
. Por exemplo, considere o cenário de querer exibir uma coleção de dados em um Grid
usando um layout associável, em que cada item da coleção é um objeto que contém várias propriedades. Cada linha no Grid
deve exibir um objeto da coleção, com cada coluna no Grid
exibindo uma das propriedades do objeto. Como o DataTemplate
para o layout associável só pode conter um único objeto, é necessário que esse objeto seja uma classe de layout contendo várias exibições que exibem cada uma das propriedades do objeto em uma coluna Grid
específica. Embora esse cenário possa ser realizado com layouts associáveis, ele resulta em um Grid
pai que contém um Grid
filho para cada item na coleção associada, que é um uso altamente ineficiente e problemático do layout Grid
.
Preencher um layout associável com dados
Um layout associável é preenchido com dados definindo sua propriedade ItemsSource
para qualquer coleção que implemente IEnumerable
e anexando-a a uma classe derivada do Layout<T>
:
<Grid BindableLayout.ItemsSource="{Binding Items}" />
Este é o código C# equivalente:
IEnumerable<string> items = ...;
var grid = new Grid();
BindableLayout.SetItemsSource(grid, items);
Quando a propriedade BindableLayout.ItemsSource
anexada é definida em um layout, mas a propriedade BindableLayout.ItemTemplate
anexada não está definida, cada item da coleção IEnumerable
será exibido por um Label
que é criado pela classe BindableLayout
.
Definir a aparência do item
A aparência de cada item no layout associável pode ser definida definindo a propriedade BindableLayout.ItemTemplate
anexada como um DataTemplate
:
<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:CircleImage Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
Este é o código C# equivalente:
DataTemplate circleImageTemplate = ...;
var stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, circleImageTemplate);
Neste exemplo, cada item da TopFollowers
coleção será exibido por uma CircleImage
exibição definida no DataTemplate
:
Para obter mais informações sobre modelos de dados, consulte Xamarin.Forms Modelos de dados.
Escolher a aparência do item em tempo de execução
A aparência de cada item no layout associável pode ser escolhida em tempo de execução, com base no valor do item, definindo a propriedade BindableLayout.ItemTemplateSelector
anexada como um DataTemplateSelector
:
<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"
BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
... />
Este é o código C# equivalente:
DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
var flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);
O DataTemplateSelector
aplicativo de exemplo usado é mostrado no exemplo a seguir:
public class TechItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate XamarinFormsTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return (string)item == "Xamarin.Forms" ? XamarinFormsTemplate : DefaultTemplate;
}
}
A classe TechItemTemplateSelector
define propriedades DefaultTemplate
e XamarinFormsTemplate
DataTemplate
que são configuradas para diferentes modelos de dados. O OnSelectTemplate
método retorna o XamarinFormsTemplate
, que exibe um item em vermelho escuro com um coração ao lado, quando o item é igual a "Xamarin.Forms". Quando o item não é igual a "Xamarin.Forms", o OnSelectTemplate
método retorna o DefaultTemplate
, que exibe um item usando a cor padrão de um Label
:
Para obter mais informações sobre seletores de modelo de dados, consulte Criando um Xamarin.Forms DataTemplateSelector.
Exibir uma cadeia de caracteres quando os dados não estiverem disponíveis
A propriedade EmptyView
pode ser definida como uma cadeia de caracteres, que será exibida por um Label
quando a propriedade ItemsSource
for null
ou quando a coleção especificada pela propriedade ItemsSource
for null
ou vazia. O XAML a seguir mostra um exemplo desse cenário:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}"
BindableLayout.EmptyView="No achievements">
...
</StackLayout>
O resultado é que, quando a coleção associada a dados fornull
, a cadeia de caracteres definida como o valor da propriedade EmptyView
é exibida:
Visualizar exibições quando os dados não estiverem disponíveis
A propriedade EmptyView
pode ser definida como um modo de exibição, que será exibido quando a propriedade ItemsSource
for null
ou quando a coleção especificada pela propriedade ItemsSource
fornull
ou vazia. Pode ser uma exibição única ou uma exibição que contém várias exibições filho. O exemplo XAML a seguir mostra a propriedade EmptyView
definida como uma exibição que contém várias exibições filho:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyView>
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
</StackLayout>
</BindableLayout.EmptyView>
...
</StackLayout>
O resultado é que, quando a coleção associada a dados fornull
, o StackLayout
e suas exibições filho são exibidas.
Da mesma forma, o EmptyViewTemplate
pode ser definido como um DataTemplate
, que será exibido quando a propriedade ItemsSource
for null
, ou quando a coleção especificada pela propriedade ItemsSource
for null
ou vazia. O DataTemplate
pode conter uma única exibição ou uma exibição que contenha várias exibições filho. Além disso, o BindingContext
do EmptyViewTemplate
será herdado do BindingContext
doBindableLayout
. O exemplo XAML a seguir mostra a propriedade EmptyViewTemplate
definida como um DataTemplate
que contém uma única exibição:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyViewTemplate>
<DataTemplate>
<Label Text="{Binding Source={x:Reference usernameLabel}, Path=Text, StringFormat='{0} has no achievements.'}" />
</DataTemplate>
</BindableLayout.EmptyViewTemplate>
...
</StackLayout>
O resultado é que, quando a coleção associada a dados é null
, o Label
no DataTemplate
é exibido:
Observação
A propriedade EmptyViewTemplate
não pode ser definida por meio de um DataTemplateSelector
.
Escolher um EmptyView em tempo de execução
Exibições que serão exibidas como um EmptyView
quando os dados não estiverem disponíveis podem ser definidas como objetos ContentView
em um ResourceDictionary
. A propriedade EmptyView
pode ser definida como uma ContentView
específica, com base em alguma lógica de negócios, em tempo de execução. O XAML a seguir mostra um exemplo desse cenário:
<ContentPage ...>
<ContentPage.Resources>
...
<ContentView x:Key="BasicEmptyView">
<StackLayout>
<Label Text="No achievements."
FontSize="14" />
</StackLayout>
</ContentView>
<ContentView x:Key="AdvancedEmptyView">
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="14" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="14" />
</StackLayout>
</ContentView>
</ContentPage.Resources>
<StackLayout>
...
<Switch Toggled="OnEmptyViewSwitchToggled" />
<StackLayout x:Name="stackLayout"
BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
...
</StackLayout>
</StackLayout>
</ContentPage>
O XAML define dois objetos ContentView
no ResourceDictionary
no nível da página, com o objeto Switch
controlando qual objeto ContentView
será definido como o valor da propriedade EmptyView
. Quando o Switch
é alternado, o manipulador de eventos OnEmptyViewSwitchToggled
executa o método ToggleEmptyView
:
void ToggleEmptyView(bool isToggled)
{
object view = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
BindableLayout.SetEmptyView(stackLayout, view);
}
O método ToggleEmptyView
define a propriedade EmptyView
do objeto stackLayout
como um dos dois objetos ContentView
armazenados no ResourceDictionary
, com base no valor da propriedade Switch.IsToggled
. Em seguida, quando a coleção associada a dados for null
, o ContentView
objeto definido como a EmptyView
propriedade será exibido: