StateContainer

Mostrar una vista específica cuando la aplicación está en un estado específico es un patrón común en cualquier aplicación móvil. Algunos ejemplos abarcan desde la creación de vistas de carga para superponerlas sobre la pantalla hasta superponerlas sobre una sección de la pantalla. Se pueden crear vistas de estado vacías para cuando no hay datos que mostrar y las vistas de estado de error se pueden mostrar cuando se produce un error.

Introducción

Las StateContainer propiedades adjuntas permiten al usuario convertir cualquier elemento de diseño como , VerticalStackLayoutHorizontalStackLayouto Grid en un diseño con reconocimiento de estado. Cada diseño con estado contiene una colección de elementos derivados de View. Estos elementos se pueden usar como plantillas para diferentes estados definidos por el usuario. Siempre que la CurrentState propiedad string se establece en un valor que coincida con la StateKey propiedad de uno de los elementos View, su contenido se mostrará en lugar del contenido principal. Cuando CurrentState se establece en null o en una cadena vacía, se muestra el contenido principal.

Note

Cuando se usa StateContainer con un Grid, los estados definidos dentro de él abarcarán automáticamente todas las filas y columnas de Grid.

Syntax

StateContainer Las propiedades se pueden usar en XAML o C#.

XAML

Incluir el espacio de nombres XAML

Para usar el kit de herramientas en XAML, es necesario agregar el siguiente xmlns a la página o vista:

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

Por lo tanto, lo siguiente:

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

Se modificaría para incluir el xmlns de la siguiente manera:

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

Uso de StateContainer

A continuación se muestra un ejemplo de interfaz de usuario creada con XAML. Esta interfaz de usuario de ejemplo está conectada al siguiente ViewModel, 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>

Marcado de C#

A continuación se muestra la misma interfaz de usuario que el XAML anterior, creada con marcado C#.

Esta interfaz de usuario de ejemplo está conectada al siguiente ViewModel, 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

Cuando se utiliza un ICommand para cambiar CurrentState (p. ej., al usar Button.Command para cambiar estados), recomendamos usar CanStateBeChanged para ICommand.CanExecute().

A continuación se muestra un ejemplo de MVVM mediante MVVM Community Toolkit:

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

De forma predeterminada StateContainer , cambia el estado sin animación. Para agregar una animación personalizada, puede usar el 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);
    }
}

Así es como funciona en iOS:

Animación de StateContainer

Propiedades

StateContainer

Las propiedades StateContainer se pueden usar en cualquier Layout elemento heredado.

Propiedad Tipo Descripción
StateViews IList<View> Los elementos disponibles View para usar como plantillas de estado.
Estado actual string Determina qué elemento View con su correspondiente StateKey se debe mostrar.

Advertencia: CurrentState no se puede cambiar mientras un cambio de estado está en curso
CanStateChange bool Cuando true, se puede cambiar la propiedad CurrentState. Cuando false, no se puede cambiar porque está cambiando actualmente.

Advertencia: Si CurrentState se cambia cuando CanStateChanged es false, se lanza una excepción StateContainerException.

StateView

Las propiedades StateView se pueden usar en cualquier View elemento heredado.

Propiedad Tipo Descripción
StateKey string Nombre del estado.

Methods

StateContainer

Método Arguments Descripción
ChangeStateWithAnimation (estático) BindableObject enlazable, cadena? state, Animation? beforeStateChange, Animación? afterStateChange, token cancellationToken Cambiar el estado con animación personalizada.
ChangeStateWithAnimation (estático) BindableObject enlazable, cadena? state, Func<VisualElement, CancellationToken, Task>? beforeStateChange, Func<VisualElement, CancellationToken, Task>? afterStateChange, CancellationToken cancellationToken Cambiar el estado con animación personalizada.
ChangeStateWithAnimation (estático) BindableObject enlazable, cadena? state, CancellationToken token Cambiar el estado con la animación de desvanecimiento predeterminada.

Ejemplos

Puede encontrar un ejemplo de esta característica en acción en la aplicación de ejemplo .NET MAUI Community Toolkit.

API

Puede encontrar el código fuente de StateContainer en el repositorio .NET MAUI Community Toolkit GitHub.