Dot.Blog

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

Xamarin.Forms: Simplifier l’intégration des images

Partager les mêmes images dans une solution est parfois fastidieux car il fait intervenir dans chaque projet natif. Y-a-t-il plus simple ? Oui, bien sûr…

Les images intégrées

YWImgePhoneNous allons utiliser des images intégrées, c’est à dire des images placées dans un fichier ressource empaqueté avec l’exécutable. Ces images à la différence de celles posées dans chaque projet possèdent l’avantage de pouvoir être partagées par toutes les plateformes. Ce qui allège le logiciel, sa distribution, sa maintenance, mais qui possède un impératif : que les images soient exactement les mêmes pour toutes les plateformes. Parfois cela est impossible et on utilisera le procédé habituel (ajout des images dans chaque projet natif), mais souvent il est possible de n’avoir qu’une image pour toutes les cibles, et c’est là que nous utiliserons des images intégrées.

Ce préambule était nécessaire pour cerner les avantages et inconvénients de la méthode proposée.

100% Xamarin.Forms

La méthode des images partagées possède comme avantage principal d’être une technique n’impliquant que le code Xamarin.Forms sans intervenir sur les codes natifs.

A mon avis, et c’est le sens de l’histoire avec MAUI (amélioration des Xamarin.Forms), le développeur ne devrait plus à notre époque avoir à se soucier des projets natifs. S’ils existent c’est juste parce qu’au début les Xamarin.Forms ne permettaient pas de tout faire et que cela laissait la porte ouverte à des personnalisations techniques intimement liées à chaque plateforme. Cela peut être encore nécessaire de nos jours mais franchement l’avenir n’est pas dans ce type de programmation, l’avenir est dans un projet unique, global, et à Microsoft de se débrouiller pour compiler correctement notre code pour chaque plateforme. C’est bien la direction prise avec MAUI (fin 2021). Mais depuis longtemps il est possible de presque tout faire côté Xamarin.Forms, et c’est ce que je préconise toujours. La technique du jour va dans ce sens.

Stockage des images

Dans le projet Xamarin.Forms il suffit de créer un répertoire “Images” et d’y ajouter les images partagées. On fera en sorte que les formats utilisés soient supportés par toutes les cibles bien entendu. La création du répertoire est facultative techniquement mais très franchement je vous conseille fortement de le créer pour organiser proprement votre projet !

Pour chaque image ajoutée à ce répertoire il va falloir s’assurer d’un point : le type d’intégration de l’objet dans le projet.

Pour ce faire on clique sur l’image dans le gestionnaire du projet, puis on active la fenêtre des propriétés (on l’affiche si elle est cachée) et on vérifie que la propriété “Build Action” est positionnée sur “EmbeddedResource”. C’est à dire “ressource intégrée”.

Etendre XAML

XAML est un langage, et il est extensible, cela est même dans son nom ! Et nous allons utiliser cette possibilité pour nous faciliter encore plus la vie.

En effet, l’utilisation en XAML des images placées en ressource n’est pas tout à fait direct. Il faudrait charger les images depuis le code behind ce qui est d’une lourdeur inacceptable. Et nous pouvons être intransigeants puisque XAML nous donne les moyens de l’être !

Ici nous allons écrire une Extension XAML qui permettra dans le code XAML d’utiliser directement le nom des images partagées. Si cela est nécessaire c‘est que par défaut les noms d’images utilisées en XAML feront référence aux images de la cible native. Or les images placées en ressource ne sont pas au même endroit. Il faut convertir le nom de l’image (texte) en ImageSource supportée par la classe Image qui affichera le fichier.  Et plutôt que d’obliger à faire cette conversion depuis le code behind, l’écriture d’une extension XAML permettra de se servir directement du nom de l’image en XAML sans aucune autre contrainte.

L’extension XAML s’écrit en C#, elle est très courte :

using System;
using System.Reflection;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace MonAppliXXX
{
    [ContentProperty (nameof(Source))]

    public class ImageResourceExtension : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
                return null;
          
            return ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
        }
    }
}


Côté XAML, dans la page utilisant la ressource partagée, il nous faudra ajouter le namespace XAML de notre extension :

xmlns:local="clr-namespace:MonAppliXXX"

Bien entendu le nom exact dépend de votre application…

Utilisation

Le plus dur étant fait il ne suffit plus que d’ajouter une balise Image dans notre XAML et de donner le nom du fichier en ressource à utiliser… Toutefois nous utiliserons au passage la notation XAML étendue puisque nous allons invoquer l’extension que nous venons d’écrire… En fait c’est un jeu d’enfant :

        <Image Source="{local:ImageResource MonAppliXXX.Images.Logo.png}" />

La source de l’image est déclarée de telle sorte à invoquer notre extension, c’est la première partie : “local:ImageResource” (namespace plus nom de la classe sans le suffixe “Extension”). Ensuite vient tout simplement le nom de l’image et c’est tout ! Ce nom est construit de la sorte :

  • Nom de l’application (ici “MonAppliXXX”)
  • Nom du répertoire des images (ici “Images”)
  • Et enfin le nom de l’image avec son extension (“Logo.png”)

Désormais l’image sera affichée le plus simplement du monde dans toutes les cibles et sans avoir à multiplier les copies de l’image ni même à avoir à intervenir dans les codes natifs !

Conclusion

Le fait que Xamarin.Forms nous offre la possibilité d’intervenir dans chaque projet natif de façon simple pour régler des problèmes qui sinon ne pourraient être traités est une force qui fait l’un des intérêts de cette plateforme depuis sa création. Mais cela se justifiait surtout au départ, il y a plusieurs années, quand les Xamarin.Forms étaient loin d’être aussi complètes qu’aujourd’hui. Demain avec MAUI les choses vont aller encore plus loin puisque nous travaillerons sur un seul projet unique sans voir les “n” projets natifs.

Mais pas besoin d’attente fin 2021 ou courant 2022 pour les premières version abouties de MAUI, un bout de code C# pour une extension XAML suffit déjà à simplifier grandement la programmation et l’unification des plateformes.

L’avenir c’est cela, un seul vrai code pour toutes les cibles sans patauger dans les renderers, effects et autres codes natifs. Xamarin.Forms nous a aider à atteindre presque 100% de cet objectif, MAUI franchira la barre. Mais nous pouvons profiter dès maintenant de l’état d’esprit unificateur.

Stay Tuned !

blog comments powered by Disqus