StateContainer

Exibir uma exibição específica quando seu aplicativo está em um estado específico é um padrão comum em qualquer aplicativo móvel. Os exemplos vão desde a criação de exibições de carregamento até a sobreposição na tela ou em uma subseção da tela. Exibições de estado vazias podem ser criadas para quando não há dados a serem exibidos e exibições de estado de erro podem ser exibidas quando ocorre um erro.

Introdução

As StateContainer propriedades anexadas permitem que o usuário transforme qualquer elemento de layout como um VerticalStackLayout, HorizontalStackLayoutou Grid em um layout com reconhecimento de estado. Cada layout sensível ao estado contém uma coleção de elementos derivados de View. Esses elementos podem ser usados como modelos para estados diferentes definidos pelo usuário. Sempre que a propriedade de CurrentState cadeia de caracteres for definida como um valor que corresponda à StateKey propriedade de um dos elementos View, seu conteúdo será exibido em vez do conteúdo principal. Quando CurrentState é definido como null ou como uma string vazia, o conteúdo principal é exibido.

Note

Ao usar StateContainer com um Grid, todos os estados definidos dentro dele abrangerão automaticamente cada linha e coluna do Grid.

Syntax

StateContainer as propriedades podem ser usadas em XAML ou C#.

XAML

Incluindo o namespace XAML

Para usar o kit de ferramentas no XAML, o xmlns a seguir precisa ser adicionado à sua página ou exibição:

xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"

Portanto, o seguinte:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

</ContentPage>

Seria modificado para incluir o xmlns da seguinte maneira:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

</ContentPage>

Usando o StateContainer

Veja abaixo um exemplo de interface do usuário criado usando XAML. Esta interface de usuário de exemplo está conectada ao ViewModel abaixo, StateContainerViewModel.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MyProject.MyStatePage"
             BindingContext="StateContainerViewModel">

    <VerticalStackLayout 
        toolkit:StateContainer.CurrentState="{Binding CurrentState}"
        toolkit:StateContainer.CanStateChange="{Binding CanStateChange}">

        <toolkit:StateContainer.StateViews>
            <VerticalStackLayout toolkit:StateView.StateKey="Loading">
                <ActivityIndicator IsRunning="True" />
                <Label Text="Loading Content..." />
            </VerticalStackLayout>
            <Label toolkit:StateView.StateKey="Success" Text="Success!" />
        </toolkit:StateContainer.StateViews>

        <Label Text="Default Content" />
        <Button Text="Change State" Command="{Binding ChangeStateCommand}" />

    </VerticalStackLayout>

</ContentPage>

Marcação em C#

Abaixo está a mesma interface do usuário do XAML acima, criada com C# Markup.

Esta IU de exemplo está conectada ao ViewModel abaixo, StateContainerViewModel.

using CommunityToolkit.Maui.Layouts;
using CommunityToolkit.Maui.Markup;

BindingContext = new StateContainerViewModel();

Content = new VerticalStackLayout()
{
    new Label()
        .Text("Default Content"),
    
    new Button()
        .Text("Change State")
        .Bind(
            Button.CommandProperty,
            static (StateContainerViewModel vm) => vm.ChangeStateCommand,
            mode: BindingMode.OneTime)
}.Bind(
    StateContainer.CurrentStateProperty,
    static (StateContainerViewModel vm) => vm.CurrentState,
    static (StateContainerViewModel vm, string currentState) => vm.CurrentState = currentState)
 .Bind(
    StateContainer.CanStateChangeProperty,
    static (StateContainerViewModel vm) => vm.CanStateChange,
    static (StateContainerViewModel vm, bool canStateChange) => vm.CanStateChange = canStateChange)
 .Assign(out VerticalStackLayout layout);

var stateViews = new List<View>()
{
    //States.Loading
    new VerticalStackLayout()
    {
        new ActivityIndicator() { IsRunning = true },
        new Label().Text("Loading Content")
    },

    //States.Success
    new Label().Text("Success!")
};

StateView.SetStateKey(stateViews[0], States.Loading);
StateView.SetStateKey(stateViews[1], States.Success);

StateContainer.SetStateViews(layout, stateViews);

static class States
{
    public const string Loading = nameof(Loading);
    public const string Success = nameof(Success);
}

ViewModel

Ao usar um(a) ICommand para alterar CurrentState (por exemplo, ao usar Button.Command para alterar estados), recomendamos usar CanStateBeChanged para ICommand.CanExecute().

Veja abaixo um exemplo de MVVM usando o Kit de Ferramentas da Comunidade MVVM:

[INotifyPropertyChanged]
public partial class StateContainerViewModel
{
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(ChangeStateCommand))]
    bool canStateChange;

    [ObservableProperty]
    string currentState = States.Loading;

    [RelayCommand(CanExecute = nameof(CanStateChange))]
    void ChangeState()
    {
        CurrentState = States.Success;
    }
}

Por padrão StateContainer , altera o estado sem animação. Para adicionar uma animação personalizada, você pode usar o ChangeStateWithAnimation método:

async Task ChangeStateWithCustomAnimation()
{
    var targetState = "TargetState";
    var currentState = StateContainer.GetCurrentState(MyBindableObject);
    if (currentState == targetState)
    {
        await StateContainer.ChangeStateWithAnimation(
            MyBindableObject,
            null,
            (element, token) => element.ScaleTo(0, 100, Easing.SpringIn).WaitAsync(token),
            (element, token) => element.ScaleTo(1, 250, Easing.SpringOut).WaitAsync(token),
            CancellationToken.None);
    }
    else
    {
        await StateContainer.ChangeStateWithAnimation(
            MyBindableObject,
            targetState,
            (element, token) => element.ScaleTo(0, 100, Easing.SpringIn).WaitAsync(token),
            (element, token) => element.ScaleTo(1, 250, Easing.SpringOut).WaitAsync(token),
            CancellationToken.None);
    }
}

É assim que funciona no iOS:

Animação de StateContainer

Propriedades

StateContainer

As propriedades StateContainer podem ser usadas em qualquer Layout elemento herdado.

Property Tipo Descrição
StateViews IList<View> Os View elementos disponíveis para serem usados como modelos de estado.
CurrentState string Determina qual View elemento com o correspondente StateKey deve ser exibido.

Aviso: CurrentState não pode ser alterado enquanto uma alteração de estado estiver em andamento
CanStateChange bool Quando true, a propriedade CurrentState pode ser alterada. Quando false, não pode ser alterado porque está sendo alterado no momento.

Aviso: se CurrentState for alterado quando CanStateChanged for false, um StateContainerException será gerado.

StateView

As propriedades stateview podem ser usadas em qualquer View elemento herdado.

Property Tipo Descrição
StateKey string Nome do estado.

Methods

StateContainer

Método Arguments Descrição
ChangeStateWithAnimation (estático) BindableObject associável, cadeia de caracteres? estado, animação? beforeStateChange, Animation? afterStateChange, token CancellationToken Alterar o estado com animação personalizada.
ChangeStateWithAnimation (estático) BindableObject bindable, string? state, Func<VisualElement, CancellationToken, Task>? beforeStateChange, Func<VisualElement, CancellationToken, Task>? afterStateChange, CancellationToken cancellationToken Alterar o estado com animação personalizada.
ChangeStateWithAnimation (estático) BindableObject associável, cadeia de caracteres? state, CancellationToken token Altere o estado usando a animação de fade padrão.

Exemplos

Você pode encontrar um exemplo desse recurso em ação no aplicativo de exemplo .NET MAUI Community Toolkit.

API

O código-fonte do StateContainer pode ser encontrado no repositório GitHub do .NET MAUI Community Toolkit.