Dot.Blog

Consulting DotNet C#, XAML, WinUI, WPF, MAUI, IA

C# Markup Extensions sous MAUI pour des UI 100% C#

Les interfaces utilisateur (UI) en XAML ont longtemps été le standard pour les applications .NET, mais que diriez-vous d'une méthode alternative tout aussi puissante, voire plus flexible ?

Le C# Markup du Community Toolkit pour MAUI permet de créer des interfaces utilisateur directement en C#, sans recourir à XAML. C'est une révolution pour ceux qui préfèrent garder leur logique et leur UI dans le même langage, tout en bénéficiant de la puissance des méthodes d'extension.

Qu'est-ce que le C# Markup du Community Toolkit pour MAUI ?

Le C# Markup est une fonctionnalité fournie par le .NET MAUI Community Toolkit qui permet de concevoir des interfaces utilisateur en utilisant uniquement du code C#. Vous allez me dire que ce n'est pas nouveau, on toujours pu le faire !. C'est vrai, mais c'était pénible, C# n'aillant pas été conçu dans cet esprit. Mais désormais à travers des méthodes d'extension intuitives, il devient possible de définir la structure, le style, et la mise en page des vues directement dans le code, sans passer par le XAML et surtout de façon ultra-fluide !

Cette approche offre plusieurs avantages, notamment une plus grande cohérence entre la logique métier et la présentation, une meilleure contrôlabilité des comportements dynamiques des composants UI, et une simplification de la maintenance du code, surtout pour les développeurs qui préfèrent éviter le mélange des langages.

Pourquoi choisir le C# Markup ?

En utilisant le C# Markup, il est possible de bénéficier de la puissance et de la flexibilité de C# pour construire des UI. Il n'est plus nécessaire de passer de XAML à C# lorsque l'on a besoin d'implémenter des comportements dynamiques complexes. Tout est dans le même langage, ce qui facilite la lecture et la gestion du code.

En plus, le C# Markup permet de tirer parti des nombreuses fonctionnalités de C#, comme les lambdas et les méthodes d'extension, pour créer des interfaces plus dynamiques et réactives. Par exemple, il est facile d'utiliser des expressions conditionnelles pour afficher ou masquer des éléments en fonction de l'état de l'application.

Les avantages de XAML pour la conception d'interfaces utilisateur

Bien que le C# Markup offre une flexibilité et une puissance indéniables, il est important de ne pas sous-estimer les atouts de XAML, qui reste un choix privilégié pour de nombreux développeurs lorsqu'il s'agit de créer des interfaces utilisateur sous .NET MAUI. XAML présente plusieurs avantages qui en font un langage incontournable dans le développement d'interfaces graphiques. Pour que cet article reste équilibré laissez-moi vous présenter les avantages de XAML sur C# Markup.

Une séparation claire entre la logique et la présentation

L'un des principaux atouts de XAML est sa capacité à séparer clairement la logique de l'application (écrite en C#) et la définition de l'interface utilisateur. Cette séparation est cruciale pour maintenir un code propre, surtout dans les projets de grande envergure où l'interface utilisateur peut devenir complexe. En isolant le code de présentation dans un fichier XAML, il est plus facile de travailler sur l'apparence de l'application sans toucher à la logique sous-jacente.

Une syntaxe déclarative et intuitive

XAML est un langage de balisage qui permet de définir les éléments d'interface de manière déclarative là où C# est un langage impératif. Cette approche est non seulement intuitive, mais elle offre également une vue d'ensemble claire de la structure de l'interface. Les développeurs peuvent facilement visualiser et modifier la hiérarchie des éléments UI, ce qui rend le développement plus rapide et plus fluide. De plus, XAML bénéficie d'un excellent support des outils de développement comme Visual Studio, qui propose des fonctionnalités de design en direct, de complétion de code, et de vérification d'erreurs en temps réel.

Une meilleure prise en charge des styles, des comportements, des propriétés

XAML excelle dans la gestion des styles, sans oublier les convertisseurs, les Behaviors etc. Grâce à son système de ressources, de styles et d'extensions variées, il est facile de définir et de réutiliser des styles, conversions et comportements cohérents à travers toute l'application et de tirer profit de sa gestion particulière des propriétés. 

La compatibilité avec MVVM et les outils de liaison de données

XAML est également parfaitement adapté au modèle MVVM (Model-View-ViewModel), qui est largement utilisé dans le développement d'applications .NET. La liaison de données (Data Binding) est un aspect clé du MVVM, et XAML offre un support natif pour cette fonctionnalité, permettant de lier facilement les propriétés des objets de vue-modèle aux éléments d'interface. Cette approche réduit la quantité de code "boilerplate" nécessaire pour synchroniser l'état de l'interface utilisateur avec la logique métier, rendant l'application plus facile à maintenir. Les propriétés de dépendances et les propriétés attachées offrent des mécanismes totalement uniques (coercition des valeurs, plusieurs couches de valeurs en même temps avec niveau de priorité, ...). Il n'existe pas d'équivalent sous C#.

Une communauté et un écosystème robustes

Enfin, XAML bénéficie d'une communauté de développeurs étendue et d'un écosystème mature. De nombreux tutoriels, bibliothèques et outils sont disponibles pour aider à résoudre les défis courants du développement d'interfaces utilisateur. Cette richesse de ressources et de support est un atout majeur pour les développeurs, qu'ils soient débutants ou expérimentés.

Alors que faut-il choisir ?

La question de savoir s'il faut choisir entre le C# Markup et XAML dépend largement de la nature du projet, des préférences personnelles du développeur, et des exigences spécifiques de l'application. Le C# Markup brille par sa capacité à centraliser la logique et l'interface dans un seul langage, offrant une flexibilité accrue pour les interfaces dynamiques ou complexes. D'autre part, XAML excelle dans la clarté de la séparation entre la présentation et la logique, ainsi que dans la gestion des styles, et de la liaison de données, ce qui en fait un choix idéal pour les interfaces visuellement riches et structurées ayant beaucoup d'interactions avec l'utilisateur.

Il n'est cependant pas nécessaire de choisir exclusivement l'un ou l'autre. Une approche mixte, combinant les deux méthodes, est non seulement possible, mais souvent recommandée. Par exemple, certaines pages de l'application, où la complexité et la réactivité sont cruciales, pourraient être entièrement codées en C# Markup. D'autres pages, nécessitant une mise en page reposant sur des styles, des Behaviors, ou une forte utilisation de la liaison de données (Binding), pourraient bénéficier de la puissance et de la lisibilité de XAML. Cette flexibilité permet de tirer le meilleur des deux mondes, en utilisant chaque outil de manière optimale selon les besoins spécifiques de l'interface à créer.

Créer une UI avec le C# Markup : un exemple pratique

L'idée du jour est de vous présenter le C# Markup et non d'ouvrir un débat sur les bienfaits relatifs de C# et XAML pour créer des UI. Je vous montre ce qu'il est possible de faire, à vous de choisir. Donc revenons à nos moutons et pour bien comprendre la puissance du C# Markup, rien de mieux qu'un exemple concret.

Imaginons que je veuille créer une interface utilisateur simple avec un label et un bouton qui, lorsqu'il est cliqué, change le texte du premier. Voici comment cela peut être fait avec le C# Markup. Mais d'abord regardons ce qu'il faudrait écrire en C# sans les extensions du Toolkit :

using Microsoft.Maui.Controls;
using System;
public class MainPage : ContentPage
{
    public MainPage()
    {
        var label = new Label
        {
            Text = "Bonjour, MAUI !",
            FontSize = 24,
            HorizontalOptions = LayoutOptions.Center
        };
        var button = new Button
        {
            Text = "Cliquez-moi",
            FontSize = 18,
            HorizontalOptions = LayoutOptions.Center
        };
        button.Clicked += (sender, e) =>
        {
            label.Text = "Bonjour, les gars !";
        };
        Content = new StackLayout
        {
            Children = {
                label,
                button
            },
            Padding = new Thickness(20),
            VerticalOptions = LayoutOptions.Center
        };
    }
}

Dans cet exemple, je définis une `Label` et un `Button` dans du code C#. Il est possible de configurer les propriétés des éléments mais ce n'est pas vraiment fluide et intuitif. C# oblige à créer chaque objet et à définir chaque propriété dans un style assez lourd. Et donc ? Utilisons maintenant les méthodes d'extension de C# Markup et cela va tout changer !

Utilisation des méthodes d'extension

Le véritable pouvoir du C# Markup réside dans ses méthodes d'extension. Ces méthodes permettent d'enchaîner les configurations de manière fluide et bien plus naturelle. Par exemple, je pourrais simplifier le code précédent en utilisant les extensions du C# Markup pour rendre le code bien plus rapide à écrire, à comprendre et à maintenir.

public MainPage()
{
    Content = new StackLayout
    {
        Padding = 20,
        VerticalOptions = LayoutOptions.Center
    }
    .Children(
        new Label()
            .Text("Bonjour, MAUI !")
            .FontSize(24)
            .CenterHorizontal(),
            
        new Button()
            .Text("Cliquez-moi")
            .FontSize(18)
            .CenterHorizontal()
            .Invoke(b => b.Clicked += (sender, e) =>
            {
                ((Label)((StackLayout)b.Parent).Children[0]).Text = "Bonjour, le monde!";
            })
    );
}

Ici, j'ai simplifié l'instanciation et la configuration des éléments enfants du Layout avec des méthodes comme .Text(), .FontSize() et .CenterHorizontal(). Le code est non seulement plus lisible, mais aussi plus expressif et facile à maintenir. On peut entendu adapoter ce type d'écriture pour la totalité de la page à afficher.

Créer des interfaces complexes avec le C# Markup

Le C# Markup ne se limite pas aux interfaces simples. Il est parfaitement adapté aux interfaces utilisateur complexes qui nécessitent des comportements dynamiques. Pour bien illustrer cela, imaginons que je souhaite créer une interface de gestion de tâches avec des boutons pour ajouter, supprimer et marquer des tâches comme complètes. Chaque tâche sera représentée par une Grid avec des Label et des Button pour l'interaction. Grâce au C# Markup, il est possible de définir et gérer cette interface en quelques lignes de code très lisibles.

using Microsoft.Maui.Controls;
using CommunityToolkit.Maui.Markup;
using System.Collections.ObjectModel;
public class TaskPage : ContentPage
{
    ObservableCollection<string> tasks = new ObservableCollection<string>();
    public TaskPage()
    {
        Content = new StackLayout
        {
            Padding = 20,
            VerticalOptions = LayoutOptions.Start
        }
        .Children(
            new Button()
                .Text("Ajouter une tâche")
                .CenterHorizontal()
                .Invoke(addButton => addButton.Clicked += OnAddTaskClicked),
            new CollectionView()
                .ItemsSource(tasks)
                .ItemTemplate(new DataTemplate(() =>
                {
                    return new Grid()
                        .Columns("*,Auto")
                        .Children(
                            new Label()
                                .Bind(Label.TextProperty, ".")
                                .FontSize(18)
                                .VerticalCenter()
                                .Margin(10, 0),
                            new Button()
                                .Text("Supprimer")
                                .Margin(10, 0)
                                .Invoke(deleteButton => deleteButton.Clicked += (sender, e) =>
                                {
                                    var button = sender as Button;
                                    var task = button?.BindingContext as string;
                                    tasks.Remove(task);
                                })
                                .End()
                        );
                }))
        );
    }
    void OnAddTaskClicked(object sender, EventArgs e)
    {
        tasks.Add($"Nouvelle tâche {tasks.Count + 1}");
    }
}

Décryptage de l'exemple

1. ObservableCollection<string> tasks : J'utilise une collection observable pour stocker les tâches. Cela permet à l'interface utilisateur de se mettre à jour automatiquement lorsqu'une tâche est ajoutée ou supprimée.

2. Le bouton Ajouter une tâche : Le bouton pour ajouter une tâche est créé avec l'extension .Text() pour définir son texte, et .CenterHorizontal() pour centrer horizontalement le bouton. La méthode .Invoke() permet d'attacher facilement un gestionnaire d'événements pour ajouter une nouvelle tâche à la collection.

3. CollectionView et ItemTemplate : J'utilise un CollectionView pour afficher la liste des tâches. Le ItemTemplate est défini en utilisant une Grid avec deux colonnes : une pour le texte de la tâche, et une pour le bouton de suppression.

4. Les méthodes d'extension du C# Markup : Grâce à des méthodes comme .Columns(), .Bind(), .FontSize(), .Margin() et .VerticalCenter(), il est possible de configurer les propriétés des éléments de manière fluide. Cela rend le code plus lisible et plus maintenable.

5. Suppression des tâches : Le bouton 'Supprimer' utilise la méthode .Invoke() pour attacher un gestionnaire d'événements qui supprime la tâche de la collection lorsqu'il est cliqué. Le contexte de liaison (BindingContext) du bouton est utilisé pour identifier la tâche à supprimer.

Conclusion

Avec cet exemple, il est possible de constater comment le C# Markup permet de créer des interfaces utilisateur complexes de manière fluide et lisible. L'utilisation des méthodes d'extension rend le code plus concis et maintient une séparation claire entre la logique de présentation et la logique métier. Le C# Markup est un outil puissant dans le développement d'applications MAUI, surtout pour ceux qui préfèrent garder tout leur code dans un seul langage. Cette approche est non seulement efficace, mais elle facilite également la gestion des projets complexes, tout en offrant une grande flexibilité pour les interfaces dynamiques.

Choisir en du C# simplifié grâce au Markup du Toolkit ou du XAML est donc affaire de goût et de besoins spécifiques au projet. En l'absence de designer visuel pour le XAML MAUI il est vrai que code pour code, les deux approches sont assez équivalentes. Pour ma part je préfère coder les UI en XAML car j'aime l'approche descriptive de ce langage. Et n'oublions pas que même sans designer visuel, XAML autorise le Hot Reload bien pratique ce que le C# Markup ne propose pas. Cela peut compter pour accélérer la mise au point d'une UI avec XAML.

Mais chaque projet est unique et chaque équipe de développement doit faire ses choix. Ici il n'y a pas de "mauvais" choix, juste deux façons d'arriver au même résultat par des approches offrant chacune des avantages et des inconvénients.

Bon code, n'oubliez pas de consuilter la documentation officielle, et ...

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !