Tutoriel : créer une visionneuse de photos simple avec WinUI 3

Notes

Pour plus d’informations sur les avantages de WinUI 3, ainsi que sur les autres options de type d’application, consultez Vue d’ensemble des options de développement d’applications.

Dans cette rubrique, nous allons suivre le processus de création d’un projet WinUI 3 dans Visual Studio, puis nous créerons une application simple d’affichage de photos. Nous utilisons des contrôles, des panneaux de disposition et la liaison de données. Par ailleurs, nous écrivons à la fois du balisage XAML (qui est déclaratif) et le code de votre choix, C# ou C++ (qui sont impératifs ou procéduraux). Utilisez le sélecteur de langage au-dessus du titre de la rubrique pour choisir C# ou C++/WinRT.

Conseil

Le code source de cette rubrique est fourni en C# et C++/WinRT. Si vous êtes développeur C++, pour plus de détails et de concepts expliquant le fonctionnement du code que nous présentons ici, consultez la documentation C++/WinRT. Les rubriques appropriées incluent Contrôles XAML, liaison à une propriété C++/WinRT, Contrôles d’éléments XAML, liaison à une collection C++/WinRT et Exemple d’application C++/WinRT d’éditeur de photos.

Étape 1 : Installer des outils pour le SDK d’application Windows

Pour configurer votre ordinateur de développement, consultez Installer des outils pour le SDK d’application Windows. Si vous le souhaitez, vous pouvez ensuite consulter Créer votre premier projet WinUI 3.

Important

Vous trouverez des rubriques consacrées aux notes de publication ainsi que la rubrique Canaux de publication du SDK d’application Windows. Des notes de publication sont disponibles pour chaque canal. Pensez à prendre connaissance des limitations et problèmes connus présentés dans ces notes de publication, car ceux-ci peuvent affecter les résultats du suivi de ce tutoriel et/ou l’exécution de l’application que nous allons créer.

Étape 2 : Créer un projet

Dans Visual Studio, créez un projet C# ou C++ (selon votre choix) à partir du modèle de projet Blank App, Packaged (WinUI 3 in Desktop). Nommez le projet SimplePhotos et (pour que votre structure de dossiers corresponde à celle décrite dans ce tutoriel) décochez la case Placer la solution et le projet dans le même répertoire. Vous pouvez cibler la version la plus récente (et non la préversion) du système d’exploitation client.

Étape 3 : Copier des fichiers de ressources

L’application que nous allons créer contient des fichiers image qui se présentent sous la forme de fichiers de ressources ; ceux-ci correspondent aux photos qu’elle affiche. Dans cette section, vous allez ajouter ces ressources à votre projet. Mais vous devez d’abord vous procurer une copie des fichiers.

  1. Par conséquent, clonez (ou téléchargez sous forme de fichier .zip) le référentiel d’exemples du SDK d’application Windows (voir WindowsAppSDK-Samples). Les fichiers de ressources que nous utiliserons se trouveront ensuite dans le dossier \WindowsAppSDK-Samples\Samples\PhotoEditor\cs-winui\Assets\Samples (utilisez ce dossier pour un projet C# et C++/WinRT). Si vous souhaitez voir ces fichiers dans le dépôt en ligne, vous pouvez accéder à WindowsAppSDK-Samples/Samples/PhotoEditor/cs-winui/Assets/Samples/.

  2. Dans l’Explorateur de fichiers, sélectionnez ce dossier Samples et copiez-le dans le Presse-papiers.

  1. Accédez à l’Explorateur de solutions dans Visual Studio. Cliquez avec le bouton droit sur le dossier Assets (enfant du nœud de projet) et cliquez sur Ouvrir le dossier dans l’Explorateur de fichiers. Le dossier Assets s’ouvre dans l’Explorateur de fichiers.

  2. Collez (dans le dossier Assets) le dossier Samples que vous venez de copier.

Étape 4 : Ajouter un contrôle GridView

Notre application doit afficher des lignes et des colonnes de photos. En d’autres termes, une grille d’images. Pour une interface utilisateur de ce type, les principaux contrôles à utiliser sont l’affichage en mode Liste et l’affichage en mode Grille.

  1. Ouvrez MainWindow.xaml. Actuellement, il contient un élément Window, qui contient lui-même un panneau de disposition StackPanel. À l’intérieur de StackPanel figure un contrôle Button, qui est relié à une méthode du gestionnaire d’événements.

    La fenêtre principale d’une application représente l’affichage que vous voyez en premier lorsque vous exécutez l’application. Dans l’application que nous allons créer, la fenêtre principale a pour fonction de charger les photos du dossier Samples et d’afficher ces images sous forme de mosaïque, avec diverses informations les concernant.

  2. Remplacez les balises StackPanel et Button par le panneau de disposition Grid et le contrôle GridView indiqué dans le listing ci-dessous.

    <Window ...>
        <Grid>
            <GridView x:Name="ImageGridView"/>
        </Grid>
    </Window>
    

    Conseil

    x:Name identifie un élément XAML pour vous permettre d’y faire référence ailleurs dans le code XAML et dans le code-behind.

  3. C#. Ouvrez MainWindow.xaml.cs et supprimez la méthode myButton_Click.

  4. C++/WinRT. Ouvrez MainWindow.xaml.h et MainWindow.xaml.cpp, et supprimez la méthode myButton_Click.

Vous pouvez générer et exécuter le code maintenant, mais à ce stade la fenêtre sera vide. Pour que le contrôle GridView affiche quelque chose, nous devons lui donner une collection d’objets à afficher. C’est ce que nous allons maintenant commencer à faire.

Pour plus d’informations sur certains des types que nous venons de mentionner, consultez Panneaux de disposition et Contrôles relatifs aux applications Windows.

Étape 5 : Modèle ImageFileInfo

Un modèle (au sens des modèles, des vues et des modèles de vue) est une classe qui, dans une certaine mesure, représente un objet ou un concept du monde réel (tel qu’un compte bancaire). Il s’agit d’une abstraction de cet objet ou de ce concept du monde réel. Dans cette section, nous allons ajouter à notre projet une nouvelle classe appelée ImageFileInfo. ImageFileInfo sera un modèle d’un fichier image, comme une photo. Cette section nous permettra de progresser vers votre objectif, à savoir l’affichage de photos dans l’interface utilisateur de l’application.

Conseil

En guise de préparation de l’exemple de code ci-dessous, nous allons introduire le terme observable. Une propriété qui peut être liée dynamiquement à un contrôle XAML (pour que l’interface utilisateur soit mise à jour chaque fois que la valeur de la propriété change) est une propriété observable. Ce concept est basé sur le modèle de conception logicielle appelé modèle observateur. Dans l’application que nous créons dans le cadre de ce tutoriel, les propriétés de notre modèle ImageFileInfo ne changeront pas. Mais nous allons malgré tout montrer comment rendre ImageFileInfo observable, en lui faisant implémenter l’interface INotifyPropertyChanged.

  1. Cliquez avec le bouton droit de la souris sur le nœud du projet (SimplePhotos) et cliquez sur Ajouter>Nouvel élément..... Sous Éléments C#>Code, sélectionnez Classe. Définissez le nom sur ImageFileInfo.cs, puis cliquez sur Ajouter.

  2. Remplacez le contenu de ImageFileInfo.cs par le listing de code ci-dessous.

    using Microsoft.UI.Xaml.Media.Imaging;
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;
    using Windows.Storage;
    using Windows.Storage.FileProperties;
    using Windows.Storage.Streams;
    
    namespace SimplePhotos
    {
        public class ImageFileInfo : INotifyPropertyChanged
        {
            public ImageFileInfo(ImageProperties properties,
                StorageFile imageFile,
                string name,
                string type)
            {
                ImageProperties = properties;
                ImageName = name;
                ImageFileType = type;
                ImageFile = imageFile;
                var rating = (int)properties.Rating;
                var random = new Random();
                ImageRating = rating == 0 ? random.Next(1, 5) : rating;
            }
    
            public StorageFile ImageFile { get; }
    
            public ImageProperties ImageProperties { get; }
    
            public async Task<BitmapImage> GetImageSourceAsync()
            {
                using IRandomAccessStream fileStream = await ImageFile.OpenReadAsync();
    
                // Create a bitmap to be the image source.
                BitmapImage bitmapImage = new();
                bitmapImage.SetSource(fileStream);
    
                return bitmapImage;
            }
    
            public async Task<BitmapImage> GetImageThumbnailAsync()
            {
                StorageItemThumbnail thumbnail = 
                    await ImageFile.GetThumbnailAsync(ThumbnailMode.PicturesView);
                // Create a bitmap to be the image source.
                var bitmapImage = new BitmapImage();
                bitmapImage.SetSource(thumbnail);
                thumbnail.Dispose();
    
                return bitmapImage;
            }
    
            public string ImageName { get; }
    
            public string ImageFileType { get; }
    
            public string ImageDimensions => $"{ImageProperties.Width} x {ImageProperties.Height}";
    
            public string ImageTitle
            {
                get => string.IsNullOrEmpty(ImageProperties.Title) ? ImageName : ImageProperties.Title;
                set
                {
                    if (ImageProperties.Title != value)
                    {
                        ImageProperties.Title = value;
                        _ = ImageProperties.SavePropertiesAsync();
                        OnPropertyChanged();
                    }
                }
            }
    
            public int ImageRating
            {
                get => (int)ImageProperties.Rating;
                set
                {
                    if (ImageProperties.Rating != value)
                    {
                        ImageProperties.Rating = (uint)value;
                        _ = ImageProperties.SavePropertiesAsync();
                        OnPropertyChanged();
                    }
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
  3. Enregistrez et fermez le fichier ImageFileInfo.cs.

Étape 6 : Définir et remplir une propriété pour une collection d’images

Dans cette section, nous allons ajouter une nouvelle propriété à la classe MainWindow. La propriété (nommée Images) sera une classe de collection contenant les images que nous voulons afficher.

  1. Définissez la propriété comme suit dans MainWindow.xaml.cs :

    ...
    using System.Collections.ObjectModel;
    ...
    namespace SimplePhotos
    {
        public sealed partial class MainWindow : Window
        {
            public ObservableCollection<ImageFileInfo> Images { get; } = 
                new ObservableCollection<ImageFileInfo>();
            ...
        }
    }
    
  2. Le code permettant de remplir la nouvelle propriété de collection avec des images est affiché dans les méthodes GetItemsAsync et LoadImageInfoAsync ci-dessous. Collez également les directives using et les deux implémentations de méthode dans MainWindow.xaml.cs. Ces méthodes sont des membres de la classe Fenêtre principale, donc collez-les à l'intérieur comme vous l'avez fait avec la propriété Images ci-dessus.

    ...
    using System.Threading.Tasks;
    using Windows.ApplicationModel;
    using Windows.Storage;
    using Windows.Storage.Search;
    ...
    private async Task GetItemsAsync()
    {
        StorageFolder appInstalledFolder = Package.Current.InstalledLocation;
        StorageFolder picturesFolder = await appInstalledFolder.GetFolderAsync("Assets\\Samples");
    
        var result = picturesFolder.CreateFileQueryWithOptions(new QueryOptions());
    
        IReadOnlyList<StorageFile> imageFiles = await result.GetFilesAsync();
        foreach (StorageFile file in imageFiles)
        {
            Images.Add(await LoadImageInfoAsync(file));
        }
    
        ImageGridView.ItemsSource = Images;
    }
    
    public async static Task<ImageFileInfo> LoadImageInfoAsync(StorageFile file)
    {
        var properties = await file.Properties.GetImagePropertiesAsync();
        ImageFileInfo info = new(properties, 
                                 file, file.DisplayName, file.DisplayType);
    
        return info;
    }
    
  3. Dans cette section, il ne nous reste plus qu’à mettre à jour le constructeur de MainWindow pour appeler GetItemsAsync.

    public MainWindow()
    {
        ...
        GetItemsAsync();
    }
    

Si vous le souhaitez, vous pouvez générer et exécuter le code maintenant (pour vous assurer que vous avez bien suivi les différentes étapes), mais il n’y a pas grand-chose à voir dans la fenêtre à ce stade. En effet, jusqu’à présent, nous avons uniquement demandé à GridView de restituer une collection d’objets de type ImageFileInfo ; et GridView ne sait pas encore comment le faire.

Rappelez-vous que la propriété Images est une collection observable d’objets ImageFileInfo. La dernière ligne de GetItemsAsync indique à GridView (qui est nommé ImageGridView) que la source de ses éléments (ItemsSource) est la propriété Images. Le travail de GridView est alors d’afficher ces éléments.

Mais nous n’avons encore rien dit à GridView à propos de la classe ImageFileInfo. Le mieux qu’il puisse faire jusqu’à présent est donc d’afficher la valeurToString de chaque objet ImageFileInfo de la collection. Et par défaut, il s’agit simplement du nom du type. Dans la section suivante, nous allons créer un modèle de données pour définir la façon dont nous voulons afficher un objet ImageFileInfo.

Conseil

J’ai précédemment utilisé le terme collection observable. Dans l’application que nous créons dans le cadre de ce tutoriel, le nombre d’images ne change pas (et comme mentionné plus haut, les valeurs des propriétés de chaque image non plus). Mais il est considéré comme une bonne pratique d’utiliser la liaison de données pour la connexion initiale de l’interface utilisateur aux données. C’est donc ce que nous allons faire.

Étape 7 : Ajouter un modèle de données

Pour commencer, nous allons utiliser un modèle de données substituable de type esquisse. Il nous servira jusqu’à ce que nous ayons fini d’explorer certaines options de disposition. Ensuite, nous pourrons mettre à jour le modèle de données pour afficher les photos.

Conseil

Cette méthode est très pratique. Il a été constaté que si une interface utilisateur ressemble à une esquisse (faible fidélité), les gens sont plus enclins à suggérer et/ou à tester des idées rapides, ce qui implique parfois des changements assez importants. Cela s’explique par le fait que nous pensons (à juste titre) que de tels changements seront peu coûteux à essayer.

D’un autre côté, plus une interface utilisateur a l’air finie (plus haute fidélité), plus nous supposons (à nouveau, à juste titre) que son apparence actuelle est le fruit de beaucoup de travail. Et cela nous incite moins à suggérer, ou à essayer, de nouvelles idées.

  1. Ouvrez MainWindow.xaml et modifiez le contenu de l’élément Window de manière à obtenir un balisage proche de celui-ci :

    <Window ...>
        <Grid>
            <Grid.Resources>
                <DataTemplate x:Key="ImageGridView_ItemTemplate">
                    <Grid/>
                </DataTemplate>
            </Grid.Resources>
            <GridView x:Name="ImageGridView"
                    ItemTemplate="{StaticResource ImageGridView_ItemTemplate}">
            </GridView>
        </Grid>
    </Window>
    

    À la racine de la disposition, nous avons ajouté une ressource DataTemplate simple, et nous lui avons attribué la clé ImageGridView_ItemTemplate. Puis nous avons utilisé cette clé pour définir la propriété ItemTemplate de GridView. Les contrôles d’éléments tels que GridView ont une propriété ItemTemplate (ainsi qu’une propriété ItemsSource, comme nous l’avons vu précédemment). Un modèle d’élément est un modèle de données et celui-ci est utilisé pour afficher chaque élément de la collection.

    Pour plus d’informations, consultez Conteneurs et modèles d’élément.

  2. Nous pouvons maintenant procéder à quelques modifications du modèle de données, en ajoutant et en modifiant les éléments qu’il contient pour le rendre plus intéressant et plus utile. Nous allons attribuer à l’élément Grid racine une hauteur et une largeur de 300, ainsi qu’une marge de 8. Puis nous ajouterons deux définitions de ligne et nous définirons la hauteur de la deuxième définition sur Auto.

    <DataTemplate x:Key="ImageGridView_ItemTemplate">
        <Grid Height="300"
              Width="300"
              Margin="8">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
        </Grid>
    </DataTemplate>
    

    Pour plus d’informations, consultez Alignement, marge, remplissage.

  3. Notre objectif est que le modèle de données affiche l’image, le nom, le type de fichier, les dimensions et l’évaluation de chaque photo. Nous allons donc ajouter, respectivement, un contrôle Image, des contrôles TextBlock et un contrôle RatingControl. Nous placerons le texte dans des panneaux de disposition StackPanel. Initialement, l’Image affichera le logo Microsoft Store du projet, sous forme d’esquisse, en tant que paramètre substituable.

  4. Après toutes ces modifications, voici à quoi ressemble le modèle de données :

    <DataTemplate x:Key="ImageGridView_ItemTemplate">
        <Grid Height="300"
              Width="300"
              Margin="8">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <Image x:Name="ItemImage"
                   Source="Assets/StoreLogo.png"
                   Stretch="Uniform" />
    
            <StackPanel Orientation="Vertical"
                        Grid.Row="1">
                <TextBlock Text="ImageTitle"
                           HorizontalAlignment="Center"
                           Style="{StaticResource SubtitleTextBlockStyle}" />
                <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center">
                    <TextBlock Text="ImageFileType"
                               HorizontalAlignment="Center"
                               Style="{StaticResource CaptionTextBlockStyle}" />
                    <TextBlock Text="ImageDimensions"
                               HorizontalAlignment="Center"
                               Style="{StaticResource CaptionTextBlockStyle}"
                               Margin="8,0,0,0" />
                </StackPanel>
    
                <RatingControl Value="3" IsReadOnly="True"/>
            </StackPanel>
        </Grid>
    </DataTemplate>
    

Vous pouvez maintenant générer le projet et exécuter l’application pour voir le contrôle GridView avec le modèle d’élément que vous venez de créer. Nous allons à présent examiner la façon dont les éléments sont disposés. Nous allons modifier certains pinceaux et ajouter de l’espace entre les éléments.

The placeholder item template.

Étape 8 : Modifier le style du conteneur d’élément

Un autre concept est lié aux contrôles d’éléments tels que GridView : le conteneur d’élément. Un conteneur d’élément est un contrôle de contenu qui affiche un élément comme valeur de sa propriété Content. Un contrôle d’éléments crée autant de conteneurs d’élément que nécessaire afin d’afficher à tout moment les éléments visibles à l’écran.

En tant que contrôle, un conteneur d’élément possède un style et un modèle de contrôle. Son style et son modèle de contrôle déterminent l’apparence du conteneur d’élément dans ses différents états (sélection, passage du pointeur, focus, etc.). Et comme nous l’avons vu, le modèle d’élément (qui est un modèle de données) détermine l’apparence de l’élément lui-même.

Concernant GridView, le type de ses conteneurs d’élément est GridViewItem.

Dans cette section, nous allons donc nous concentrer sur la conception du style du conteneur d’élément. Pour cela, nous allons créer une ressource Style pour GridViewItem, puis la définir en tant que ItemContainerStyle de *GridView. Dans le style, nous allons définir les propriétés Background and Margin du conteneur d’élément pour lui attribuer un fond gris et l’entourer d’une petite marge.

  1. Dans MainWindow.xaml, ajoutez une nouvelle ressource Style au même élément XML Grid.Resources que celui dans lequel nous avons placé le modèle de données.

    <Grid>
        <Grid.Resources>
        ...
            <Style x:Key="ImageGridView_ItemContainerStyle"
                TargetType="GridViewItem">
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Margin" Value="8"/>
            </Style>
        </Grid.Resources>
    
  2. Ensuite, nous utilisons la clé ImageGridView_ItemContainerStyle pour définir la propriété ItemContainerStyle de GridView.

    <GridView x:Name="ImageGridView"
            ...
            ItemContainerStyle="{StaticResource ImageGridView_ItemContainerStyle}">
    </GridView>
    

Créez et exécutez l’application, et regardez comment elle se présente désormais. Lorsque vous redimensionnez la fenêtre, GridView se charge de réorganiser les éléments en fonction de l’espace disponible. Pour certaines largeurs, il reste beaucoup d’espace sur le côté droit de la fenêtre d’application. Il serait préférable de centrer l’élément GridView et/ou son contenu. C’est ce que nous allons faire maintenant.

Conseil

Si vous souhaitez faire des essais, attribuez aux propriétés Background et Margin des valeurs différentes pour voir l’effet obtenu.

Étape 9 : Effectuer des essais de disposition

Vous vous demandez peut-être s’il est préférable de centrer l’élément GridView lui-même ou de centrer son contenu. Essayons d’abord de centrer GridView.

  1. Pour faciliter la visualisation de l’emplacement exact de GridView dans la fenêtre, et de ce qui se passe lorsque nous faisons des essais de disposition, nous allons définir sa propriété Background sur la couleur rouge.

    <GridView x:Name="ImageGridView"
            ...
            Background="Red">
    </GridView>
    
  2. Et maintenant, nous allons définir sa propriété HorizontalAlignment sur Center.

    <GridView x:Name="ImageGridView"
            ...
            HorizontalAlignment="Center">
    </GridView>
    

    Consultez également Alignement, marge, remplissage.

Générez et exécutez maintenant le code, et faites des essais d’ajustement de la largeur de la fenêtre. Vous pouvez voir qu’il y a une quantité égale d’espace vide de chaque côté du fond rouge de GridView. Nous avons donc atteint notre objectif qui consistait à centrer les images. Mais il est maintenant plus évident qu’auparavant que la barre de défilement appartient à GridView, et non à la fenêtre. Nous devons donc faire en sorte que GridView remplisse à nouveau la fenêtre. Nous avons démontré qu’au lieu de centrer GridView dans la fenêtre, nous devons centrer les images dans GridView.

  1. Par conséquent, supprimez l’attribut HorizontalAlignment que vous avez ajouté à l’étape précédente.

Étape 10 : Modifier le modèle de panneau d’éléments

Les contrôles d’éléments placent leurs conteneurs d’élément à l’intérieur de ce que l’on appelle un panneau d’éléments. Nous pouvons définir le type de panneau utilisé et configurer les propriétés de ce panneau en modifiant le modèle de panneau d’éléments de GridView. C’est donc ce que nous allons faire dans cette section.

  1. Dans MainWindow.xaml, ajoutez une ressource ItemsPanelTemplate au dictionnaire de ressources. Le panneau d’éléments est de type ItemsWrapGrid, et nous définissons sa propriété HorizontalAlignment sur Center.

    <Grid>
        <Grid.Resources>
        ...
            <ItemsPanelTemplate x:Key="ImageGridView_ItemsPanelTemplate">
                <ItemsWrapGrid Orientation="Horizontal"
                               HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </Grid.Resources>
    
  2. Nous utilisons ensuite la clé ImageGridView_ItemsPanelTemplate pour définir la propriété ItemsPanel de GridView.

    <GridView x:Name="ImageGridView"
            ...
            ItemsPanel="{StaticResource ImageGridView_ItemsPanelTemplate}">
    </GridView>
    

Cette fois, lorsque vous générez et exécutez le code, et que vous essayez d’ajuster la largeur de la fenêtre, il y a une quantité égale de fond rouge de GridView de chaque côté des images. Et étant donné que GridView remplit la fenêtre, la barre de défilement est bien alignée sur le bord de la fenêtre, là où les utilisateurs s’attendent à la trouver.

  1. Maintenant que nous avons fini d’expérimenter la disposition, vous pouvez supprimer Background="Red" de GridView.

Étape 11 : Remplacer l’image d’espace réservé par une photo

Il est maintenant temps de faire passer notre esquisse à un niveau de fidélité supérieur, ce qui signifie qu’il faut remplacer l’image substituable par une image réelle, et remplacer le texte substituable de type « lorem ipsum » par des données réelles. Occupons-nous d’abord des images.

Important

La technique que nous allons utiliser pour afficher les photos du dossier Assets\Samples consiste à mettre à jour les éléments de GridView de manière progressive. Plus précisément, il s’agit du code dans les méthodes ImageGridView_ContainerContentChanging et ShowImage de l’exemple de code ci-dessous, notamment l’utilisation des propriétés ContainerContentChangingEventArgs.InRecycleQueue et ContainerContentChangingEventArgs.Phase. Pour plus d’informations, consultez Optimisation de l’interface utilisateur de ListView et de GridView. Mais en bref, GridView nous indique (par le biais d’un événement) quand l’un de ses conteneurs d’élément est prêt à afficher son élément. Ensuite, nous allons suivre la phase de son cycle de vie de mise à jour dans laquelle se trouve le conteneur d’élément afin de pouvoir déterminer quand il est prêt à afficher les données photo.

  1. Dans MainWindow.xaml.cs, ajoutez à MainWindow une nouvelle méthode nommée ImageGridView_ContainerContentChanging. Il s’agit d’une méthode de gestion d’événements, et l’événement qu’elle gère est ContainerContentChanging. Nous devons également fournir l’implémentation de la méthode ShowImage dont dépend ImageGridView_ContainerContentChanging. Collez la directive using et les deux implémentations de méthode dans MainWindow.xaml.cs :

    ...
    using Microsoft.UI.Xaml.Controls;
    ...
    private void ImageGridView_ContainerContentChanging(
        ListViewBase sender,
        ContainerContentChangingEventArgs args)
    {
        if (args.InRecycleQueue)
        {
            var templateRoot = args.ItemContainer.ContentTemplateRoot as Grid;
            var image = templateRoot.FindName("ItemImage") as Image;
            image.Source = null;
        }
    
        if (args.Phase == 0)
        {
            args.RegisterUpdateCallback(ShowImage);
            args.Handled = true;
        }
    }
    
    private async void ShowImage(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if (args.Phase == 1)
        {
            // It's phase 1, so show this item's image.
            var templateRoot = args.ItemContainer.ContentTemplateRoot as Grid;
            var image = templateRoot.FindName("ItemImage") as Image;
            var item = args.Item as ImageFileInfo;
            image.Source = await item.GetImageThumbnailAsync();
        }
    }
    
  1. Ensuite, dans MainWindow.xaml, inscrivez le gestionnaire d’événements ImageGridView_ContainerContentChanging auprès de l’événement ContainerContentChanging de GridView.

    <GridView x:Name="ImageGridView"
            ...
            ContainerContentChanging="ImageGridView_ContainerContentChanging">
    </GridView>
    

Étape 12 : Remplacer le texte d’espace réservé par des données réelles

Dans cette section, nous allons utiliser des liaisons de données ponctuelles. Une liaison ponctuelle est idéale pour les données qui ne changent pas au moment de l’exécution. Et cela signifie que les liaisons ponctuelles sont très performantes et faciles à créer.

  1. Dans MainWindow.xaml, recherchez la ressource de modèle de données ImageGridView_ItemTemplate. Nous allons indiquer au modèle de données que son rôle est d’être un modèle pour la classe ImageFileInfo qui, comme vous vous en souvenez sûrement, est le type des éléments qu’affiche GridView.

  2. Pour ce faire, ajoutez une valeur x:DataType au modèle, comme suit :

    <DataTemplate x:Key="ImageGridView_ItemTemplate"
                  x:DataType="local:ImageFileInfo">
        ...
    

    Si vous ne maîtrisez pas la syntaxe local: présentée ci-dessus (ou la syntaxe xmlns:local déjà présente dans la balise d’ouverture Window), consultez Espaces de noms XAML et mappage d’espaces de noms.

    Maintenant que nous avons défini un x:DataType, nous pouvons utiliser des expressions de liaison de données x:Bind dans le modèle de données pour établir une liaison avec des propriétés du type de données que nous avons spécifié (en l’occurrence, ImageFileInfo).

  3. Dans le modèle de données, recherchez le premier élément TextBlock (celui dont la propriété Text est actuellement définie sur ImageTitle). Remplacez sa valeur Text comme indiqué ci-dessous.

    Conseil

    Vous pouvez copier et coller le balisage ci-dessous, ou utiliser IntelliSense dans Visual Studio. Pour ce faire, sélectionnez la valeur actuelle qui se trouve à l’intérieur des guillemets, puis saisissez {. IntelliSense ajoute automatiquement l’accolade fermante et affiche une liste de saisie semi-automatique. Vous pouvez faire défiler la liste jusqu’à x:Bind et double-cliquer dessus. Mais il peut être plus efficace de saisir x: (notez comment x:Bind est ensuite filtré en haut de la liste de complétion semi-automatique) et d’appuyer sur la touche TAB. Appuyez maintenant sur la touche ESPACE, saisissez ImageT (autant de fois que nécessaire pour faire apparaître le nom de propriété ImageTitle en haut de la liste de saisie semi-automatique) et appuyez sur TAB.

    <TextBlock Text="{x:Bind ImageTitle}"
        ... />
    

    Une expression x:Bind lie la valeur d’une propriété d’interface utilisateur à la valeur d’une propriété d’objet de données. Bien sûr, cela dépend de la définition préalable de x:DataType sur le type de cet objet de données, afin que les outils et le runtime sachent quelles propriétés sont disponibles pour la liaison.

    Pour plus d’informations, consultez Extension de balisage {x:Bind} et Présentation détaillée de la liaison de données.

  4. De la même manière, remplacez les valeurs des autres propriétés TextBlock et RatingControl. Voici le résultat :

    <TextBlock Text="{x:Bind ImageTitle}" ... />
    <StackPanel ... >
        <TextBlock Text="{x:Bind ImageFileType}" ... />
        <TextBlock Text="{x:Bind ImageDimensions}" ... />
    </StackPanel>
    <RatingControl Value="{x:Bind ImageRating}" ... />
    

Si vous générez et exécutez l’application maintenant, vous verrez de vraies photos et du vrai texte (ainsi que d’autres données) à la place des paramètres substituables. Visuellement et fonctionnellement parlant, cette petite application toute simple est maintenant terminée. Mais en guise de coda, faisons un dernier petit travail de liaison de données.

The finished app.

Étape 13 : Lier GridView à la collection Images (C# uniquement)

Important

Effectuez cette dernière étape uniquement si vous avez créé un projet C#.

Conseil

Vous constaterez qu’il est impossible d’effectuer certaines choses (généralement liées à l’interface utilisateur générée dynamiquement) dans le balisage XAML. Mais en règle générale, si vous en avez la possibilité, il est préférable de faire quelque chose dans le balisage. Cela permet d’obtenir une séparation un peu plus nette entre la vue que le balisage XAML représente et le modèle (ou le modèle de vue) que le code impératif représente. Et cela tend à améliorer le flux de travail dans les outils et entre les membres de l’équipe.

Nous utilisons actuellement du code impératif pour associer la propriété ItemsSource de GridView à la propriété Images de MainWindow. Mais nous pouvons aussi le faire dans le balisage.

  1. Dans la classe MainWindow, supprimez (ou commentez) la dernière ligne de GetItemsAsync, qui définit le paramètre ItemsSource de ImageGridView sur la valeur de la propriété Images.

  2. Dans MainWindow.xaml, recherchez l’élément GridView nommé ImageGridView et ajoutez un attribut ItemsSource. Si vous le souhaitez, vous pouvez utiliser IntelliSense pour effectuer cette modification.

    <GridView x:Name="ImageGridView"
              ...
              ItemsSource="{x:Bind Images}"
    

Pour cette application, la valeur de la propriété Images ne change pas au moment de l’exécution. Mais comme Images est de type ObservableCollection<T>, le contenu de la collection peut changer (autrement dit, des éléments peuvent être ajoutés ou supprimés). La liaison détectera alors automatiquement les modifications et mettra à jour l’interface utilisateur.

Conclusion

Dans ce tutoriel, nous avons suivi le processus d’utilisation de Visual Studio pour créer une application WinUI 3 simple qui affiche des photos. Nous espérons que ce tutoriel vous a permis d’acquérir de l’expérience sur les contrôles, les panneaux de disposition, la liaison de données et l’optimisation de l’interface utilisateur GridView au sein d’une application WinUI 3.

Voir aussi

Tutoriel : Créer une visionneuse de photos simple qui cible plusieurs plateformes