Share via


BindableLayout

Browse sample. Procurar no exemplo

Os layouts associáveis do .NET Multi-Platform App UI (.NET MAUI) permitem que qualquer classe de layout derivada da classe Layout gere seu conteúdo associando-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 itens IEnumerable a serem exibidos pelo layout.
  • ItemTemplate – especifica o DataTemplate a ser aplicado a cada item na coleção de itens exibidos pelo layout.
  • ItemTemplateSelector – especifica o DataTemplateSelector que será usado para escolher um DataTemplate 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 o string ou a exibição que será visualizada quando a propriedade ItemsSource for null ou quando a coleção especificada pela propriedade ItemsSource for null ou vazia. O valor padrão é null.
  • EmptyViewTemplate – especifica o DataTemplate que será exibido quando a propriedade ItemsSource for null ou quando a coleção especificada pela propriedade ItemsSource for null 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 classes AbsoluteLayout, FlexLayout, Grid, HorizontalStackLayout, StackLayout e VerticalStackLayout que derivam da classe Layout.

Quando a propriedade BindableLayout.ItemsSource é definida como uma coleção de itens e anexada a uma classe derivada do Layout, cada item da coleção é adicionado à classe derivada do Layout para exibição. A classe derivada do Layout atualizará suas exibições filho quando a coleção subjacente for alterada.

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 classe Layout, nem sempre é prático fazer isso, especialmente para as classes AbsoluteLayout e Grid. 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:

<Grid BindableLayout.ItemsSource="{Binding Items}" />

Este é o código C# equivalente:

IEnumerable<string> items = ...;
Grid 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>
            <Image Source="{Binding}"
                   Aspect="AspectFill"
                   WidthRequest="44"
                   HeightRequest="44"
                   ... />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

Este é o código C# equivalente:

DataTemplate imageTemplate = ...;
StackLayout stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, imageTemplate);

Neste exemplo, cada item da coleção TopFollowers será exibido por uma exibição Image definida no DataTemplate:

.NET MAUI bindable layout with a DataTemplate.

Para obter mais informações sobre modelos de dados, consulte 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 { ... };
FlexLayout flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);

O exemplo a seguir mostra a classe TechItemTemplateSelector:

public class TechItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate MAUITemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return (string)item == ".NET MAUI" ? MAUITemplate : DefaultTemplate;
    }
}

A classe TechItemTemplateSelector define as propriedades DefaultTemplate e MAUITemplate do DataTemplate como modelos de dados diferentes. O método OnSelectTemplate retorna o MAUITemplate, que exibe um item em vermelho escuro com um coração ao lado dele, quando o item é igual a ".NET MAUI". Quando o item não é igual a ".NET MAUI", o método OnSelectTemplate retorna o DefaultTemplate, que exibe um item usando a cor padrão de um Label:

.NET MAUI bindable layout with a DataTemplateSelector.

Para obter mais informações sobre seletores de modelo de dados, consulte Criar um 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:

Screenshot of a bindable layout string empty view.

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

Screenshot of a bindable layout empty view with multiple views.

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:

Screenshot of a bindable layout empty view template.

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 é null, o objeto ContentView definido como a propriedade EmptyView é exibido.