Esercitazione: Creare un semplice visualizzatore foto con WinUI 3

Nota

Per informazioni sui vantaggi di WinUI 3, oltre ad altre opzioni relative al tipo di app, consultare Panoramica delle opzioni di sviluppo di app.

In questo argomento viene illustrato il processo di creazione di un nuovo progetto WinUI 3 in Visual Studio; e poi viene creata un’app semplice per visualizzare le foto. Verranno usati controlli, pannelli di layout e data binding. Verrà inoltre scritto sia il markup XAML (dichiarativo) sia la scelta del codice C# o C++ (imperativo oprocedurale). Usare la selezione del linguaggio sopra il titolo dell'argomento per scegliere C# o C++/WinRT.

Suggerimento

Il codice sorgente in questo argomento viene fornito sia in C# che in C++/WinRT. Se sei uno sviluppatore C++, per altri dettagli e concetti che spiegano il funzionamento del codice illustrato qui, consultare la documentazione di C++/WinRT. Gli argomenti pertinenti includono Controlli XAML, associati a una proprietà C++/WinRT, Controlli di elementi XAML, associati a una raccolta C++/WinRT e Applicazione di esempio C++/WinRT per Photo Editor.

Passaggio 1: Installare gli strumenti per Windows App SDK

Per configurare il computer di sviluppo, consultare Installare gli strumenti per Windows App SDK. Facoltativamente, è possibile seguire la procedura per Creare il primo progetto WinUI 3.

Importante

Sono disponibili argomenti sulle note di rilascio insieme all'argomento Canali di rilascio di Windows App SDK. Sono disponibili note sulla versione per ogni canale. Assicurati di controllare eventuali limitazioni e problemi presenti in queste note sulla versione, poiché questi potrebbero influire sui risultati delle operazioni seguenti insieme a questa esercitazione e/o all'esecuzione dell'app che verrà creata.

Passaggio 2: Creare un nuovo progetto

In Visual Studio puoi creare un nuovo progetto C# o C++ a scelta dal modello di progetto App vuota, In pacchetto (WinUI 3 su Desktop). Denominare il progetto SimplePhotos e (facendo in modo che la struttura delle cartelle corrisponda a quella descritta in questa esercitazione) deselezionare Inserisci soluzione e progetto nella stessa directory. Puoi specificare come destinazione la versione più recente (non l'anteprima) del sistema operativo client.

Passaggio 3: Copiare i file di asset

L'app che verrà creata contiene file di immagine sotto forma di file di asset; e quelle sono le foto che mostra. In questa sezione verranno aggiunti tali asset al progetto. Ma prima è necessario ottenere una copia dei file.

  1. Clonare (o scaricare come .zip) il repository degli esempi di Windows App SDK (consultare WindowsAppSDK-Samples). A questo scopo, troverai i file di asset che verranno usati nella cartella \WindowsAppSDK-Samples\Samples\PhotoEditor\cs-winui\Assets\Samples (usare questa cartella sia per un progetto C# che per un progetto C++/WinRT). Se vuoi visualizzare i file nel repository online, puoi visitare WindowsAppSDK-Samples/Samples/PhotoEditor/cs-winui/Assets/Samples/.

  2. In Esplora file selezionare la cartella Esempi e copiarla negli Appunti.

  1. Consultare Esplora soluzioni in Visual Studio. Fare clic con il pulsante destro del mouse sulla cartella Asset (figlio del nodo del progetto) e scegliere Apri cartella in Esplora file. Verrà aperta la cartella Asset in Esplora file.

  2. Incollare (nella cartella Asset) la cartella Esempi appena copiata.

Passaggio 4: Aggiungere un controllo GridView

L'app deve visualizzare righe e colonne di foto. In altre parole, una griglia di immagini. Per un'interfaccia utente di questo tipo, i controlli principali da usare sono Visualizzazione elenco e visualizzazione griglia.

  1. MainWindow.xaml aperti. Attualmente, è presente un elemento Window e all'interno di tale pannello di layout StackPanel. All'interno di StackPanel c’è un controllo Button, collegato a un metodo del gestore eventi.

    La finestra principale di qualsiasi app rappresenta la visualizzazione visualizzata per la prima volta quando si esegue l'app. Nell'app che stiamo creando, il processo della finestra principale consiste nel caricare le foto dalla cartella Esempi e visualizzare una visualizzazione affiancata di tali immagini insieme a varie informazioni collegate.

  2. Sostituire il markup StackPanel e Button con il pannello layout Griglia e il controllo GridView mostrato nell'elenco seguente.

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

    Suggerimento

    x:Name identifica un elemento XAML in modo che tu possa farvi riferimento in un altro punto del codice XAML e nel code-behind.

  3. C#. Aprire MainWindow.xaml.cs ed eliminare il metodo myButton_Click.

  4. C++/WinRT. Aprire MainWindow.xaml.h e MainWindow.xaml.cpp ed eliminare il metodo myButton_Click.

Ora puoi creare ed eseguire, ma la finestra sarà vuota in questa fase. Perché il controllo GridView visualizzi gli elementi dobbiamo assegnargli una raccolta di oggetti da visualizzare. Questo sarà lo step successivo.

Per informazioni generali su alcuni dei tipi appena menzionati, consulta Pannelli di layout e Controlli per le app di Windows.

Passaggio 5: Modello ImageFileInfo

Un modello (nel senso di modelli, visualizzazioni e modelli di visualizzazione) è una classe che in qualche modo rappresenta un oggetto o un concetto reale (ad esempio un conto bancario). È un'astrazione di quella cosa reale. In questa sezione verrà aggiunta al progetto una nuova classe denominata ImageFileInfo. ImageFileInfo sarà un modello di un file di immagine, ad esempio una foto. Questa sezione ci porterà un passo più vicino alla possibilità di visualizzare le foto nell'interfaccia utente dell'app.

Suggerimento

In preparazione dell'esempio di codice riportato di seguito, verrà introdotto il termine osservabile. Una proprietà che può essere associata dinamicamente a un controllo XAML (in modo che l'interfaccia utente venga aggiornata ogni volta che il valore della proprietà cambia) è nota come proprietà osservabile. Questo concetto è basato sul modello di progettazione del software noto come modello osservatore. Nell'app compilata in questa esercitazione le proprietà del modello ImageFileInfo non cambieranno. Tuttavia, anche in questo caso, verrà illustrato come rendere osservabile ImageFileInfo, implementando l'interfaccia INotifyPropertyChanged.

  1. Fare clic con il pulsante destro del mouse sul nodo del progetto (SimplePhotos) e scegliere Aggiungi>Nuovo elemento.... In Elementi C#>Codice, selezionare Classe. Impostare il nome su ImageFileInfo.cse fare clic su Aggiungi.

  2. Sostituisci il contenuto di ImageFileInfo.cs con il listato di codice riportato di seguito.

    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. Salva e chiude il file ImageFileInfo.cs.

Passaggio 6: Definire e popolare una proprietà per una raccolta di immagini

In questa sezione verrà aggiunta una nuova proprietà alla classe MainWindow. La proprietà (denominata Images) sarà una classe di raccolta che contiene le immagini da visualizzare.

  1. Definire la proprietà come questa in MainWindow.xaml.cs:

    ...
    using System.Collections.ObjectModel;
    ...
    namespace SimplePhotos
    {
        public sealed partial class MainWindow : Window
        {
            public ObservableCollection<ImageFileInfo> Images { get; } = 
                new ObservableCollection<ImageFileInfo>();
            ...
        }
    }
    
  2. Il codice per popolare la nuova proprietà della raccolta con le immagini è illustrato nei metodi GetItemsAsync e LoadImageInfoAsync seguenti. Incollare anche le direttive using e le due implementazioni del metodo in MainWindow.xaml.cs. Questi metodi sono membri della classe MainWindow, quindi incollali all'interno proprio come hai fatto con la proprietà Immagini precedente.

    ...
    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. L'ultima operazione da eseguire in questa sezione consiste nell'aggiornare il costruttore di MainWindow per chiamare GetItemsAsync.

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

Ora è possibile creare ed eseguire se lo si desidera (per confermare di aver seguito bene i passaggi), ma non c'è molto da vedere nella finestra in questa fase. Questo perché ciò che abbiamo fatto finora è chiedere a GridView di eseguire il rendering di una raccolta di oggetti di tipo ImageFileInfo e GridView non sa ancora come farlo.

Tenere presente che la proprietà Images è una raccolta osservabile di oggetti ImageFileInfo. E l'ultima riga di GetItemsAsync indica a GridView(denominato ImageGridView) che l'origine dei relativi elementi (ItemsSource) è la proprietà Immagini. E il processo di GridView consiste nel visualizzare tali elementi.

Ma non abbiamo ancora detto nulla a GridView sulla classe ImageFileInfo. Quindi al momento è in grado solo di visualizzare il valore ToString di ogni oggetto ImageFileInfo nella raccolta. Per impostazione predefinita, questo è solo il nome del tipo. Nella sezione successiva verrà creato un modello di dati per definire la modalità di visualizzazione di un oggetto ImageFileInfo.

Suggerimento

Ho usato il termine raccolta osservabile sopra. Nell'app compilata in questa esercitazione il numero di immagini non cambia (e come abbiamo detto, né i valori delle proprietà di ogni immagine). Tuttavia, è comunque utile e consigliabile usare il data binding per connettere inizialmente l'interfaccia utente ai dati. Quindi è quello che faremo.

Passaggio 7: Aggiungere un modello di dati

Per iniziare, useremo un modello di dati segnaposto simile a una bozza. Verrà usato fino a quando non verrà completata l'esplorazione di alcune opzioni di layout. Dopo di che è possibile aggiornare il modello di dati per visualizzare le foto effettive.

Suggerimento

In realtà è una cosa molto pratica da fare. È stato riscontrato che se un'interfaccia utente ha un aspetto simile a una bozza (in altre parole, a bassa fedeltà), le persone sono più disposte a suggerire e/o testare idee rapide. A volte questo comporta cambiamenti piuttosto sostanziali. Questo perché supponiamo (correttamente) che tali modifiche saranno economiche da provare.

D'altra parte, più è finito un aspetto dell'interfaccia utente (e maggiore è la fedeltà), più supponiamo (di nuovo, correttamente) che molto lavoro sia finito nel suo aspetto attuale. E questo ci rende meno propensi a suggerire, o a provare, nuove idee.

  1. Aprire MainWindow.xaml e modificare il contenuto della finestra in modo che abbia un aspetto simile al markup seguente:

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

    Alla radice del layout abbiamo aggiunto una semplice risorsa DataTemplate e dato la chiave di ImageGridView_ItemTemplate. E abbiamo usato la stessa chiave per impostare ItemTemplate di GridView. I controlli di elementi, come GridView, hanno una proprietà ItemTemplate (proprio come hanno la proprietà ItemsSource illustrata in precedenza). Un modello di elemento è un modello di dati; e viene usato per visualizzare ogni elemento nella raccolta.

    Per altre info, consultare Contenitori di elementi e modelli.

  2. Ora possiamo eseguire alcuni passaggi di modifica sul modello di dati, aggiungendo e modificando gli elementi al suo interno per renderlo più interessante e utile. Alla radice Griglia assegniamo un'altezza e una larghezza pari a 300 e un margine pari a 8. Poi aggiungiamo due definizioni di riga e impostiamo l'altezza della seconda definizione di riga su Auto.

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

    Per altre info, consultare Allineamento, margine, spaziatura interna.

  3. Vogliamo che il modello di dati visualizzi l'immagine, il nome, il tipo di file, le dimensioni e la classificazione di ogni foto. Verranno quindi aggiunti, rispettivamente, un controllo Image, alcuni controlli TextBlock e un controllo RatingControl. Disporremo il testo all'interno dei pannelli di layout StackPanel. L'immagine inizialmente visualizzerà il logo Microsoft Store tipo bozza del progetto come un segnaposto.

  4. Dopo tutte queste modifiche, l’aspetto del modello di dati risulta come segue:

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

Ora creare il progetto ed eseguire l'app per visualizzare il controllo GridView con il modello di elemento appena creato. Successivamente, esamineremo il modo in cui vengono disposti gli elementi. Verranno modificati alcuni pennelli e aggiungeremo spazio tra gli elementi.

The placeholder item template.

Passaggio 8: Modificare lo stile del contenitore di elementi

Un altro concetto correlato a controlli dii elementi come GridView, è il contenitore di elementi. Un contenitore di elementi è un controllo contenuto che visualizza un elemento come valore della relativa proprietà Contenuto. Un controllo elementi crea tutti i contenitori di elementi necessari per visualizzare gli elementi visibili sullo schermo in qualsiasi momento.

Essendo un controllo, un contenitore di elementi ha uno stile e un modello di controllo. Il modello di stile e controllo determina l'aspetto del contenitore di elementi nei vari stati, ad esempio la selezione, il puntatore e lo stato attivo. Inoltre, come si è visto, il modello di elemento (che è un modello di dati) determina l'aspetto dell'elemento stesso.

Per GridView, il tipo di contenitori di elementi è GridViewItem.

In questa sezione verrà quindi illustrato come progettare lo stile del contenitore di elementi. Per questo creiamo una risorsa Stile per GridViewItemche imposteremo come ItemContainerStyle di *GridView. Nello stile imposteremo le proprietà Sfondo e Margine del contenitore di elementi per assegnargli uno sfondo grigio e un po' di margine intorno all'esterno.

  1. In MainWindow.xaml, viene aggiunta una nuova risorsa Stile allo stesso elemento XML Grid.Resources in cui è stato inserito il modello di dati.

    <Grid>
        <Grid.Resources>
        ...
            <Style x:Key="ImageGridView_ItemContainerStyle"
                TargetType="GridViewItem">
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Margin" Value="8"/>
            </Style>
        </Grid.Resources>
    
  2. Successivamente usiamo la chiave ImageGridView_ItemContainerStyle per impostare ItemContainerStyle di GridView.

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

Crea ed esegui l'app per vederne l'aspetto. Quando si ridimensiona la finestra, il controllo GridView si occupa della riorganizzazione degli elementi in modo da adattarsi meglio allo spazio. Ad alcune larghezze, c'è molto spazio sul lato destro della finestra dell'app. Sarebbe meglio se GridView e/o il relativo contenuto fossero centrati. Lo faremo più avanti.

Suggerimento

Se vuoi provare, imposta le proprietà Sfondo e Margine su valori diversi e vedi l'impatto delle modifiche.

Passaggio 9: Esperimento con il layout

Ci si potrebbe chiedere se è meglio centrare lo stesso GridView o centrarne il contenuto. Prova prima a centrare GridView.

  1. Per semplificare la visualizzazione di GridView nella finestra, e ciò che accade durante l'esperimento con il layout, la proprietà Sfondo verrà impostata in rosso.

    <GridView x:Name="ImageGridView"
            ...
            Background="Red">
    </GridView>
    
  2. A questo punto la proprietà HorizontalAlignment verrà impostata su Centro.

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

    Consultare anche Allineamento, margine, spaziatura interna.

Ora puoi creare ed eseguire e provare a regolare la larghezza della finestra. C’è una quantità uguale di spazio vuoto su entrambi i lati dello sfondo rosso di GridView. Ora abbiamo raggiunto l'obiettivo di centrare le immagini. Ma ora è più chiaro di prima che la barra di scorrimento appartenga a GridView e non alla finestra. È quindi necessario modificare GridView per riempire la finestra. È stato dimostrato che (invece di centrare GridView nella finestra) è necessario centrare le immagini in GridView.

  1. Eliminare quindi l'attributo HorizontalAlignment aggiunto nel passaggio precedente.

Passaggio 10: Modificare il modello del pannello elementi

I controlli di elementi ripongono i contenitori di elementi all'interno di ciò che è noto come il pannello elementi. Possiamo definire il tipo di pannello usato e impostare le proprietà nel pannello modificando il modello del pannello elementi di GridView. Ecco cosa faremo in questa sezione.

  1. In MainWindow.xaml, aggiungiamo una risorsa ItemsPanelTemplate al dizionario risorse. Il pannello degli elementi è del tipo ItemsWrapGride la proprietà HorizontalAlignment viene impostata su Centro.

    <Grid>
        <Grid.Resources>
        ...
            <ItemsPanelTemplate x:Key="ImageGridView_ItemsPanelTemplate">
                <ItemsWrapGrid Orientation="Horizontal"
                               HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </Grid.Resources>
    
  2. Successivamente, usiamo la chiave ImageGridView_ItemsPanelTemplate per impostare ItemsPanel di GridView.

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

Quando crei ed esegui questa volta, e provi a regolare la larghezza della finestra, c'è una quantità uguale dello sfondo rosso di GridView su entrambi i lati delle immagini. E poiché GridView riempie la finestra, la barra di scorrimento si allinea perfettamente al bordo della finestra, dove gli utenti potrebbero aspettarsi che si trovi.

  1. Dopo aver completato l'esperimento con il layout, rimuovere Background="Red"da GridView.

Passaggio 11: Sostituire l'immagine segnaposto con una foto

Ora è il momento di far passare la nostra bozza a un livello di fedeltà più alto; e ciò significa sostituire l'immagine segnaposto con quelle reali e sostituendo il testo segnaposto "lorem ipsum" con dati reali. In primo luogo dobbiamo pensare alle immagini.

Importante

La tecnica che verrà usata per visualizzare le foto nella cartella Assets\Samples comporta l'aggiornamento progressivo degli elementi di GridView. In particolare, questo è il codice nei metodi ImageGridView_ContainerContentChanging e ShowImage nell'esempio di codice seguente, incluso l'uso delle proprietà ContainerContentChangingEventArgs.InRecycleQueue e ContainerContentChangingEventArgs.Phase. Per altre informazioni, vedi Ottimizzazione dell'interfaccia utente in ListView e GridView. In sintesi, GridView ci informerà (tramite un evento) quando uno dei contenitori di elementi è pronto per visualizzarne l'elemento. Terremo traccia della fase del ciclo di vita dell'aggiornamento del contenitore di elementi in modo da poter stabilire quando è pronto per visualizzare i dati delle foto.

  1. In MainWindow.xaml.cs, aggiungere un nuovo metodo a MainWindow denominato ImageGridView_ContainerContentChanging. Si tratta di un metodo di gestione degli eventi e l'evento gestito è ContainerContentChanging. Dobbiamo anche fornire l'implementazione del metodo ShowImage da cui ImageGridView_ContainerContentChanging dipende. Incollare la direttiva using e le due implementazioni del metodo in 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. Poi in MainWindow.xaml registrare il gestore eventi ImageGridView_ContainerContentChanging con l'evento ContainerContentChanging di GridView.

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

Passaggio 12: Sostituire il testo segnaposto con dati reali

In questa sezione useremo il data binding una tantum. Il binding una tantum è ideale per i dati che non cambiano in fase di esecuzione. Ciò significa che i binding una tantum sono ad alte prestazioni e facili da creare.

  1. In MainWindow.xaml, trovare la risorsa modello di dati ImageGridView_ItemTemplate. Ora diremo al modello di dati che il suo compito è quello di essere un modello per la classe ImageFileInfo. Quello che richiamerai è il tipo degli elementi visualizzati da GridView.

  2. A tale scopo, aggiungere un x:DataType valore al modello, come illustrato di seguito:

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

    Se non hai familiarità con la sintassi local: illustrata in precedenza (o con la sintassi xmlns:local già presente nel tag Finestra di apertura ), consultare Mapping di spazi dei nomi XAML e dello spazio dei nomi.

    Ora che abbiamo impostato un x:DataType, possiamo usare espressioni di data binding x:Bind nel modello di dati da associare alle proprietà del tipo di dati specificato (ImageFileInfo, in questo caso).

  3. Nel modello di dati troviamo il primo elemento TextBlock (quello con il relativo Testo attualmente impostato su ImageTitle). Sostituire il valore Testo come illustrato di seguito.

    Suggerimento

    Puoi copiare e incollare il markup seguente oppure usare IntelliSense in Visual Studio. A tale scopo, selezionare il valore attuale all'interno delle virgolette e digitare {. IntelliSense aggiunge automaticamente la parentesi graffa di chiusura e visualizza un elenco di completamento del codice. Potresti scorrere verso il basso fino a x:Bind e fare doppio clic. Ma potrebbe essere più efficace digitare x: (in tal caso x:Bind viene filtrato all'inizio dell'elenco di completamento) e premere il tasto TAB. Ora premere il tasto SPAZIO e digitare ImageT (poiché gran parte del nome della proprietà ImageTitle è necessario per arrivare all'inizio dell'elenco di completamento) e TAB.

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

    Un'espressione x:Bind collega il valore di una proprietà dell'interfaccia utente con il valore di una proprietà dell'oggetto dati. Questo ovviamente dipende dalla prima impostazione x:DataType al tipo di oggetto dati in modo che gli strumenti e il runtime sappiano quali proprietà sono disponibili per l'associazione.

    Per ulteriori informazioni, consultare Estensione di markup {x:Bind} e Data binding approfondito.

  4. Allo stesso modo, sostituire i valori degli altri oggetti TextBlocke RatingControl. Il risultato è il seguente:

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

Se ora crei ed esegui l'app, invece di segnaposto vedrai foto reali e testo reale (e altri dati). Visivamente e funzionalmente, questa semplice app ora è completa. Tuttavia, come finale, faremo l’ultima parte di data binding.

The finished app.

Passaggio 13: Associare GridView alla raccolta Immagini (solo C#)

Importante

Eseguire questo ultimo passaggio solo se hai creato un progetto C#.

Suggerimento

Noterai che ci sono alcune cose (in genere correlate all'interfaccia utente generata dinamicamente) che non puoi eseguire nel markup XAML. Ma in generale, se puoi fare qualcosa nel markup, allora è preferibile. Offre una separazione leggermente più chiara tra la visualizzazione rappresentata dal markup XAML e il modello (o modello di visualizzazione) rappresentato dal codice imperativo. E questo tende a migliorare il flusso di lavoro negli strumenti e tra i membri del team.

Attualmente usiamo il codice imperativo per associare la proprietà ItemsSource diGridView alla proprietà Immagini di MainWindow. Ma possiamo farlo nel markup.

  1. Nella classe MainWindow eliminare (o commentare) l'ultima riga di GetItemsAsync, che imposta ItemsSource di ImageGridView sul valore della proprietà Immagini.

  2. Poi in MainWindow.xaml, trova l'elemento GridView denominato ImageGridView e aggiungi un attributo ItemsSource simile. Puoi usare IntelliSense per apportare questa modifica se preferisci.

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

Il valore della proprietà Immagini non cambia in fase di esecuzione per questa app specifica. Tuttavia, poiché Immagini è di tipo ObservableCollection<T>, il contenuto della raccolta può cambiare (ovvero gli elementi possono essere aggiunti o eliminati) e il binding noterà automaticamente le modifiche e aggiornerà l'interfaccia utente.

Conclusione

In questa esercitazione è stato illustrato il processo d’uso di Visual Studio per creare una semplice app WinUI 3 che visualizza le foto. Speriamo che questa esercitazione ti abbia fornito esperienza nell'uso di un'app WinUI 3 con controlli, pannelli di layout, data binding e ottimizzazione dell'interfaccia utente GridView.

Vedi anche

Esercitazione: Creare un semplice visualizzatore foto destinato a più piattaforme