Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

MAUI StateContainer pour des mise en page plus vivantes

Aujourd'hui je vous propose de découvrez comment utiliser le StateContainer du .NET MAUI Toolkit pour gérer efficacement les états visuels dans vos applications multiplateformes et de le comparer au Visual State Manager.

Introduction au StateContainer du .NET MAUI Toolkit

Le développement d'applications multiplateformes avec .NET MAUI permet d'aborder une multitude de cas d'utilisation, mais gérer l'affichage dynamique en fonction de l'état de l'application peut vite devenir un casse-tête. Le StateContainer, composant fourni par le .NET Community Toolkit MAUI, est spécialement conçu pour répondre à ce besoin. Il offre une manière élégante et centralisée de gérer l'affichage des vues en fonction de l'état courant de l'application.

Avant de plonger dans les détails du StateContainer, il est important de savoir comment installer le .NET Community Toolkit MAUI dans votre projet.

Installation du .NET Community Toolkit MAUI

Pour utiliser le StateContainer dans votre projet MAUI, vous devez d'abord installer le .NET Community Toolkit MAUI. Voici comment procéder :

1. Ajouter le package NuGet : Ouvrez votre projet MAUI et accédez à la console du gestionnaire de packages ou utilisez l'interface graphique de Visual Studio. Tapez la commande suivante pour ajouter le package :

dotnet add package CommunityToolkit.Maui

2. Initialiser le toolkit : Après l'installation du package, vous devez initialiser le toolkit dans la méthode MauiProgram.cs de votre projet :

using CommunityToolkit.Maui;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit(); // Initialiser le Community Toolkit
return builder.Build();
}
}

Une fois cette configuration effectuée, vous êtes prêt à utiliser le StateContainer et les autres composants du toolkit dans votre application MAUI.

Le StateContainer : Un Conteneur pour Gérer les États Visuels

Le StateContainer permet de conditionner l'affichage de vues spécifiques en fonction de l'état de votre application. Cela signifie que, selon les conditions définies, différentes vues peuvent être affichées pour le même composant UI.

Exemple Simple Sans MVVM

Pour commencer, voyons un exemple très simple de l'utilisation du StateContainer sans utiliser le pattern MVVM. Dans cet exemple, nous allons créer une interface qui affiche un message différent selon que l'utilisateur a appuyé sur un bouton.

Voici comment cela peut être réalisé en XAML uniquement :

<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="MyApp.Views.SimpleStateContainerPage"
Title="Simple StateContainer Example">
<toolkit:StateContainer State="{Binding IsButtonClicked, Source={x:Reference Page}}">
<toolkit:StateContainer.StateViews>
<!-- État par défaut, avant que le bouton ne soit cliqué -->
<toolkit:StateView State="False">
<Label Text="Cliquez sur le bouton pour continuer."
HorizontalOptions="Center"
VerticalOptions="Center" />
<Button Text="Cliquer"
HorizontalOptions="Center"
VerticalOptions="Center"
Command="{Binding OnButtonClickCommand, Source={x:Reference Page}}" />
</toolkit:StateView>
<!-- État après que le bouton ait été cliqué -->
<toolkit:StateView State="True">
<Label Text="Merci d'avoir cliqué sur le bouton!"
HorizontalOptions="Center"
VerticalOptions="Center" />
</toolkit:StateView>
</toolkit:StateContainer.StateViews>
</toolkit:StateContainer>
</ContentPage>

Et dans le fichier code-behind (SimpleStateContainerPage.xaml.cs), vous pouvez gérer l'état de manière très simple :

public partial class SimpleStateContainerPage : ContentPage
{
public bool IsButtonClicked { get; set; } = false;
public Command OnButtonClickCommand { get; }
public SimpleStateContainerPage()
{
InitializeComponent();
OnButtonClickCommand = new Command(OnButtonClick);
BindingContext = this;
}
private void OnButtonClick()
{
IsButtonClicked != IsButtonClicked;
OnPropertyChanged(nameof(IsButtonClicked));
}
}

Dans cet exemple, avant que l'utilisateur ne clique sur le bouton, le StateContainer affiche un message invitant l'utilisateur à cliquer sur le bouton. Une fois que le bouton est cliqué, l'état change, et un nouveau message est affiché. Cet exemple montre comment le StateContainer peut être utilisé de manière simple sans implémenter le pattern MVVM, ce que je ne vous conseille pas mais qui permet d'avoir une première approche sans trop de code.

Exemple MVVM avec StateContainer

D'ailleurs allons un peu plus loin et pour illustrer l'utilisation du StateContainer en situation réelle, utilisons-le en suivant le pattern MVVM (Model-View-ViewModel) dans une application .NET MAUI. Voyons un exemple complet et simple. Cet exemple montrera comment charger des données depuis une API tout en gérant différents états  de l'UI (chargement, succès, erreur) grâce au StateContainer. Forcément, il a plus de code, mais on se rapproche plus d'une utilisation normale du contrôle dans une vraie App.

Structure du Projet

Assurez-vous d'avoir une structure de projet en place avec les éléments suivants :

  • Models : pour représenter les données.
  • ViewModels : pour la logique de présentation et la gestion des états.
  • Views : pour l'interface utilisateur.

Création du Modèle (Model)

Commençons par créer une classe pour représenter les données. Par exemple, si vous chargez une liste de produits :

public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}

Création du ViewModel

Le ViewModel va gérer l'état de l'application et interagir avec le service de données pour charger les produits. Il utilisera l'interface INotifyPropertyChanged pour notifier les vues des changements d'état.

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public class ProductsViewModel : ObservableObject
{
private bool isLoading;
private bool hasError;
private ObservableCollection<Product> products;
public bool IsLoading
{
get => isLoading;
set => SetProperty(ref isLoading, value);
}
public bool HasError
{
get => hasError;
set => SetProperty(ref hasError, value);
}
public ObservableCollection<Product> Products
{
get => products;
set => SetProperty(ref products, value);
}
public IRelayCommand LoadProductsCommand { get; }
public ProductsViewModel()
{
Products = new ObservableCollection<Product>();
LoadProductsCommand = new AsyncRelayCommand(LoadProductsAsync);
}
private async Task LoadProductsAsync()
{
IsLoading = true;
HasError = false;
try
{
// Simule le chargement des données
await Task.Delay(2000);
var loadedProducts = new List<Product>
{
new Product { Id = 1, Name = "Product 1", Price = 10.0 },
new Product { Id = 2, Name = "Product 2", Price = 20.0 }
};
Products.Clear();
foreach (var product in loadedProducts)
{
Products.Add(product);
}
}
catch
{
HasError = true;
}
finally
{
IsLoading = false;
}
}
}

Création de la Vue (View)

La vue va consommer le ViewModel et utiliser le StateContainer pour gérer les différents états visuels. Voici un exemple en XAML :

<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="MyApp.Views.ProductsPage"
Title="Products">
<ContentPage.BindingContext>
<local:ProductsViewModel />
</ContentPage.BindingContext>
<toolkit:StateContainer State="{Binding IsLoading}">
<toolkit:StateContainer.StateViews>
<!-- Vue de chargement -->
<toolkit:StateView State="True">
<ActivityIndicator IsRunning="True" />
<Label Text="Loading products..." HorizontalOptions="Center" VerticalOptions="Center" />
</toolkit:StateView>
<!-- Vue en cas de succès -->
<toolkit:StateView State="False" Condition="{Binding HasError, Converter={StaticResource InverseBooleanConverter}}">
<ListView ItemsSource="{Binding Products}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" Detail="{Binding Price, StringFormat='Price: {0:C}'}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</toolkit:StateView>
<!-- Vue en cas d'erreur -->
<toolkit:StateView State="False" Condition="{Binding HasError}">
<Label Text="Failed to load products. Please try again." HorizontalOptions="Center" VerticalOptions="Center" />
</toolkit:StateView>
</toolkit:StateContainer.StateViews>
</toolkit:StateContainer>
</ContentPage>

Initialisation et Utilisation

Assurez-vous que votre App.xaml.cs ou MauiProgram.cs initialise correctement le CommunityToolkit.Maui comme indiqué précédemment.

public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit(); // Initialiser le Community Toolkit
return builder.Build();
}
}

Résultat Final

Lors de l'exécution de l'application :

  1. Chargement : Lorsque l'utilisateur lance le chargement des produits, l'état IsLoading passe à true, et la vue de chargement s'affiche.
  2. Succès : Si les données sont chargées avec succès, l'état IsLoading passe à false, et la liste des produits est affichée.
  3. Erreur : En cas d'échec (par exemple, une exception pendant le chargement), l'état HasError passe à true, et un message d'erreur est affiché.

Comparaison avec le Visual State Manager (VSM)

Le Visual State Manager (VSM) est un autre outil disponible dans .NET MAUI pour gérer l'état de l'interface utilisateur. Il permet de définir et d'appliquer des états visuels spécifiques aux contrôles en fonction de certaines conditions. Bien que le VSM soit un outil puissant, il diffère du StateContainer à plusieurs égards.

Avantages du StateContainer

  • Gestion Centralisée des États : Le StateContainer encapsule l'ensemble de la logique de gestion d'état dans un seul conteneur, ce qui simplifie grandement la gestion et la maintenance du code. Il est particulièrement efficace pour les vues complexes où plusieurs états doivent être gérés simultanément.
  • Flexibilité des Vues : Le StateContainer permet de définir des vues complètement différentes en fonction de l'état, offrant ainsi une grande flexibilité pour personnaliser l'affichage.

Avantages du Visual State Manager

  • Intégration à "grain fin" : Le VSM permet une gestion plus fine des états visuels d'un composant unique, en modifiant les propriétés des contrôles en fonction de l'état. Il est idéal pour ajuster des aspects spécifiques de l'interface utilisateur comme la couleur, la taille, ou la visibilité de certains éléments.
  • Compatibilité Directe avec XAML : Le VSM est directement intégré dans XAML, c'est une option native (voir mes articles et vidéos à ce sujet)  ce qui le rend facile à utiliser pour des ajustements rapides de l'interface sans avoir besoin de créer des conteneurs séparés.

Inconvénients du StateContainer

  • Lourdeur pour les Modifications Mineures : Pour des ajustements simples comme le changement de couleur ou de visibilité d'un élément, l'utilisation du StateContainer peut être excessive par rapport au VSM. Mais très honnêtement pour de tels changements minimes, un simple Binding pourra faire le job dans de nombreux cas (mais pas si on doit fixer des propriétés spécifiques de l'UI, le ViewModel ne doit pas y toucher).
  • Nécessite un Conteneur Supplémentaire : Contrairement au VSM, qui s'intègre directement dans les contrôles, le StateContainer nécessite l'ajout d'un conteneur supplémentaire (lui-même), ce qui peut complexifier la hiérarchie de l'interface. En XAML de façon générale imbriquer trop de conteneurs les uns dans les autres pénalise la fluidité et les temps de chargement des pages.

Inconvénients du Visual State Manager

  • Moins Adapté aux Scénarios Complexes : Bien qu'il soit très sophistiqué, et paradoxalement, Le VSM est moins adapté pour gérer des changements d'état complexes impliquant des modifications majeures de la structure de la vue.
  • Éclatement de la Logique d'État : Le VSM peut entraîner une dispersion de la logique de gestion d'état à travers plusieurs contrôles, rendant la maintenance plus difficile.

Conclusion

Le StateContainer du .NET Community Toolkit MAUI est un outil puissant pour gérer les affichages conditionnels dans vos applications. En fonction de l'état de l'application, il vous permet d'afficher des vues spécifiques de manière simple et centralisée, améliorant ainsi l'expérience utilisateur et la maintenabilité de votre code. Il n'a besoin que d'un Etat exprimé par une chaîne de caractères pour fonctionner et sa configuration apparait plus légère et moins alambiquée que celle du VSM (qui reste un outil précieux notamment au sein de la définition de styles complexes).

Que vous ayez besoin d'afficher une vue de chargement, de gérer des états vides ou de traiter des erreurs, le StateContainer vous offre une solution flexible et robuste. Comparé au Visual State Manager, il apporte une approche plus structurée pour les scénarios complexes d'affichage conditionnel, bien qu'il soit moins adapté pour les ajustements mineurs et les états visuels fins.

Pour en savoir plus sur ce composant, je vous recommande de consulter la documentation officielle et d'expérimenter avec les exemples de code fournis.

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !