Share via


Tutorial: Creación de un visor de fotos simple con WinUI 3

Nota:

Para obtener información sobre las ventajas de WinUI 3 y ver otras opciones de tipo de aplicación, consulte Información general sobre las opciones de desarrollo de aplicaciones.

En este tema se explica el proceso de creación de un nuevo proyecto de WinUI 3 en Visual Studio y cómo crear una aplicación sencilla para mostrar fotos. Se usarán controles, paneles de diseño y enlace de datos. Escribiremos tanto el marcado XAML (que es declarativo) como la elección de código de C# o C++ (que es imperativo o un procedimiento). Use el selector de lenguaje encima del título del tema para elegir C# o C++/WinRT.

Sugerencia

El código fuente de este tema se proporciona en C# y C++/WinRT. Si es desarrollador de C++, para obtener más detalles y conceptos que explican cómo funciona el código que se muestra aquí, consulte la documentación de C++/WinRT. Los temas relevantes incluyen controles XAML; enlazar a una propiedad de C++/WinRT, controles de elementos XAML; enlazar a una colección de C++/WinRT y aplicación de ejemplo de Photo Editor C++/WinRT.

Paso 1: Instalación de herramientas para el SDK de Aplicaciones para Windows

Para configurar el equipo de desarrollo, consulte Instalación de herramientas para el SDK de Aplicaciones para Windows. Opcionalmente, puede seguir con el paso Creación del primer proyecto de WinUI 3.

Importante

Encontrará temas de notas de la versión junto con el tema Canales de versión del SDK de Aplicaciones para Windows. Hay notas de la versión para cada canal. Asegúrese de consultar las limitaciones y los problemas conocidos en esas notas de la versión, ya que pueden afectar los resultados que se devuelven al seguir este tutorial o a la ejecución de la aplicación que crearemos.

Paso 2: Crear un proyecto

En Visual Studio, cree su elección de un nuevo proyecto C# o C++ a partir de la plantilla de proyecto Aplicación vacía empaquetada (WinUI 3 en escritorio). Asigne al proyecto el nombre SimplePhotos y, para que la estructura de carpetas coincida con la que se describe en este tutorial, desactive Colocar la solución y el proyecto en el mismo directorio. Puede tener como destino la versión más reciente (no en versión preliminar) del sistema operativo cliente.

Paso 3: Copiar archivos de recursos

La aplicación que vamos a compilar lleva archivos de imagen en forma de archivos de recursos, y esas son las fotos que va a mostrar. En esta sección, agregará esos recursos a su proyecto. Pero primero, deberá obtener una copia de los archivos.

  1. Por lo tanto, clone el repositorio de ejemplos del SDK de Aplicaciones para Windows o descárguelo como .zip (consulte WindowsAppSDK-Samples). Después de hacerlo, encontrará los archivos de los recursos que usaremos en la carpeta \WindowsAppSDK-Samples\Samples\PhotoEditor\cs-winui\Assets\Samples (utilice esta carpeta para un proyecto C# y C++/WinRT). Si quiere ver esos archivos en el repositorio en línea, puede visitar WindowsAppSDK-Samples/Samples/PhotoEditor/cs-winui/Assets/Samples/.

  2. En el Explorador de archivos, seleccione la carpeta Ejemplos y cópiela en el Portapapeles.

  1. Abra el Explorador de soluciones en Visual Studio. Haga clic con el botón derecho en la carpeta Recursos (tenga en cuenta que es un elemento secundario del nodo del proyecto) y haga clic en Abrir carpeta en el Explorador de archivos. Se abrirá la carpeta Recursos en el Explorador de archivos.

  2. Pegue en la carpeta Recursos la carpeta Ejemplos que acaba de copiar.

Paso 4: Agregar un control GridView

La aplicación debe mostrar filas y columnas de fotos. Es decir, una cuadrícula de imágenes. En una interfaz de usuario como esta, los controles principales que se van a usar son Vista de lista y vista de cuadrícula.

  1. Abra MainWindow.xaml. Actualmente, hay un elemento Window y dentro de este un panel de diseño stackPanel. En el panel StackPanel hay un control Button, que se enlaza a un método de controlador de eventos.

    La ventana principal de cualquier aplicación representa la vista que ve primero al ejecutar la aplicación. En la aplicación que va a compilar, el trabajo de la ventana principal es cargar las fotos de la carpeta Ejemplos y mostrar una vista en mosaico de esas imágenes junto con información sobre ellas.

  2. Reemplace el marcado de StackPanel y Button con el panel de diseño Grid y el control GridView que se muestra en la lista que tiene a continuación.

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

    Sugerencia

    x:Name identifica un elemento XAML, de manera que pueda hacer referencia al mismo en otro lugar del XAML y en el código subyacente.

  3. C#. Abra MainWindow.xaml.cs y elimine el método myButton_Click.

  4. C++/WinRT. Abra MainWindow.xaml.h y MainWindow.xaml.cpp, y elimine el método myButton_Click.

Ya puede realizar la compilación y la ejecución, pero la ventana estará vacía en esta fase. Para que el control GridView muestre algo, es preciso asignarle la colección de datos que debe mostrar. Para ello, empezaremos a trabajar con este paso.

Para obtener información general sobre algunos de los tipos que acabamos de mencionar, consulte Paneles de diseño y Controles para aplicaciones Windows.

Paso 5: El modelo ImageFileInfo

Un modelo (en el sentido de los modelos, las vistas y los modelos de vista) es una clase que hasta cierto punto representa un objeto o concepto del mundo real (como una cuenta bancaria). Es una abstracción de esa cosa del mundo real. En esta sección, agregaremos a nuestro proyecto una nueva clase denominada ImageFileInfo. ImageFileInfo será un modelo de un archivo de imagen, como una foto. Gracias a esta sección estará un paso más cerca de poder mostrar fotos en la interfaz de usuario (UI) de la aplicación.

Sugerencia

Para preparar el ejemplo de código siguiente, escriba el término observable. Una propiedad que se puede enlazar dinámicamente a un control XAML (para que la interfaz de usuario se actualice cada vez que cambia el valor de propiedad) se conoce como una propiedad observable. Esta idea se basa en el patrón de diseño de software conocido como patrón observador. En la aplicación que compilará en este tutorial, las propiedades del modelo ImageFileInfo no cambiarán. Pero incluso así, le mostraremos cómo hacer que ImageFileInfo sea observable; para ello, tiene que implementar la interfaz INotifyPropertyChanged.

  1. Haga clic con el botón derecho en el nodo del proyecto (SimplePhotos) y, a continuación, en Agregar>Nuevo elemento.... En Elementos de C#>Código, seleccione Clase. Establezca el nombre en ImageFileInfo.cs y haga clic en Agregar.

  2. Reemplaza el contenido de ImageFileInfo.cs por el código siguiente.

    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. Guarda y cierra el archivo ImageFileInfo.cs.

Paso 6: Definición y rellenado de una propiedad para una colección de imágenes

En esta sección, agregaremos una nueva propiedad a la clase MainWindow. La propiedad (denominada Images) será una clase de colección que contiene las imágenes que queremos mostrar.

  1. Defina la propiedad de la siguiente manera en MainWindow.xaml.cs:

    ...
    using System.Collections.ObjectModel;
    ...
    namespace SimplePhotos
    {
        public sealed partial class MainWindow : Window
        {
            public ObservableCollection<ImageFileInfo> Images { get; } = 
                new ObservableCollection<ImageFileInfo>();
            ...
        }
    }
    
  2. El código para rellenar la nueva propiedad de colección con imágenes se muestra en los métodos GetItemsAsync y LoadImageInfoAsync siguientes. Pegue también las directivas using y las dos implementaciones de método en MainWindow.xaml.cs. Estos métodos son miembros de la clase MainWindow, así que péguelos dentro tal como hizo con la propiedad Images anterior.

    ...
    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. Lo último que tiene que hacer en esta sección es actualizar el constructor de MainWindow para llamar a GetItemsAsync.

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

Puede empezar ahora con el proceso de compilación y ejecución si quiere (para confirmar que ha seguido los pasos de forma correcta), pero no hay mucho que ver en la ventana en esta fase. Esto se debe a que lo que hemos ha hasta ahora es pedir a GridView que represente una colección de objetos de tipo ImageFileInfo; por lo tanto, GridView aún no sabe cómo realizar este proceso.

Recuerde que la propiedad Images es una colección observable de objetos ImageFileInfo. La última línea de GetItemsAsync indica a GridView (que se denomina ImageGridView) que el origen de sus elementos (ItemsSource) es la propiedad Images. Por lo tanto, el trabajo de GridView es mostrar esos elementos.

De todos modos, aún no ha indicado nada a GridView sobre la clase ImageFileInfo. Así pues, lo mejor que puede hacer es mostrar el valor ToString de cada objeto ImageFileInfo de la colección. De forma predeterminada, ese valor solo es el nombre del tipo. En la sección siguiente, tendrá que crear una plantilla de datos para definir cómo quiere que se muestre un objeto ImageFileInfo.

Sugerencia

He usado el término colección observable anterior. En la aplicación que se compiló en este tutorial, el número de imágenes no cambia (y como ya se ha indicado, tampoco cambian los valores de las propiedades de cada imagen). Pero sigue siendo conveniente (y una buena práctica) usar el enlace de datos para conectar inicialmente la interfaz de usuario a los datos. Así que eso es lo que haremos.

Paso 7: Agregar una plantilla de datos

Para empezar, use una plantilla de datos de marcador de posición similar a un boceto. Esto le servirá hasta que haya terminado de explorar algunas opciones de diseño. Después, puede actualizar la plantilla de datos para mostrar las fotos reales.

Sugerencia

Eso es algo realmente práctico. Sabemos que si una interfaz de usuario parece un boceto (en otras palabras, tiene baja fidelidad), los usuarios están más dispuestos a sugerir o probar ideas rápidas con ella y, a veces, estas sugerencias implican cambios sustanciales. Eso es porque suponemos (correctamente) que será barato probar tales cambios.

Por otro lado, cuanto más terminada se vea una interfaz de usuario (cuanta mayor fidelidad tenga), más nos parecerá (nuevamente, correctamente) que se ha trabajado mucho en su apariencia actual. Debido a ello, seremos menos propensos a sugerir o probar nuevas ideas.

  1. Abra MainWindow.xaml y cambie el contenido de la ventana para que tenga un aspecto similar a este marcado:

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

    En la raíz del diseño debe agregar un recurso DataTemplate simple y darle una clave de ImageGridView_ItemTemplate. Asimismo, hemos usado esa misma clave para establecer el elemento itemTemplate de GridView. Los controles de elementos como GridView tienen una propiedad ItemTemplate (igual que tienen la propiedad ItemsSource que vimos anteriormente). Una plantilla de elemento es una plantilla de datos y se usa para mostrar cada elemento de la colección.

    Para obtener más información, consulte Contenedores y plantillas de elementos.

  2. Ya puede realizar algunos pasos de edición en la plantilla de datos; por ejemplo, puede agregar y editar los elementos que contiene la plantilla para que sean más interesantes y útiles. Le daremos a la raíz Cuadrícula una altura y un ancho de 300, y un margen de 8. Luego tendrá que agregar dos definiciones de fila y establecer la altura de la definición de la segunda fila en Auto.

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

    Para obtener más información, consulte Alineación, margen y espaciado.

  3. Recuerde que es recomendable que la plantilla de datos muestre la imagen, el nombre, el tipo de archivo, las dimensiones y la clasificación de cada foto. Por lo tanto, tiene que agregar, respectivamente, un control Image, algunos controles TextBlock y un control RatingControl. Diseñaremos el texto de los paneles de diseño stackPanel. La imagen mostrará, inicialmente, un logotipo de Microsoft Store similar al croquis del proyecto como marcador de posición.

  4. Después hacer de todas esas modificaciones, esta es la apariencia de la plantilla de datos:

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

Compile el proyecto y ejecute la aplicación para ver el control GridView con la plantilla de elementos que acaba de crear. A continuación, eche un vistazo a la manera de diseñar los elementos. Tendrá que cambiar algunos pinceles y agregar espacio entre los elementos.

The placeholder item template.

Paso 8: Edición del estilo del contenedor de elementos

Otro concepto relacionado con los controles de elementos como GridView es el contenedor de elementos. Un contenedor de elementos es un control de contenido que muestra un elemento como valor de su propiedad Content. Un control de elementos crea tantos contenedores de elementos como necesite para mostrar los elementos que están visibles en la pantalla en cualquier momento.

Si es un control, un contenedor de elementos tiene un estilo y una plantilla de control. Su plantilla de estilo y control determina cómo se ve el contenedor de elementos en sus distintos estados (por ejemplo, al seleccionar algún elemento, colocar el puntero sobre contenido y el foco). Por lo tanto y, como ya ha visto, la plantilla de elemento (que es una plantilla de datos) determina el aspecto del elemento.

En el caso de GridView, el tipo de sus contenedores de elementos es GridViewItem.

Así pues, en esta sección nos centraremos en diseñar el estilo del contenedor de elementos. Para ello, tiene que crear un recurso Style para GridViewItem y, a continuación, establecerlo como ItemContainerStyle de *GridView. En el estilo, establezca las propiedades Background y Margin del contenedor de elementos para darle un fondo gris y un poco de margen alrededor del exterior.

  1. En MainWindow.xaml, agregue un nuevo recurso Style al mismo elemento XML Grid.Resources en el que colocó la plantilla de datos.

    <Grid>
        <Grid.Resources>
        ...
            <Style x:Key="ImageGridView_ItemContainerStyle"
                TargetType="GridViewItem">
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Margin" Value="8"/>
            </Style>
        </Grid.Resources>
    
  2. A continuación, use la clave ImageGridView_ItemContainerStyle para establecer itemContainerStyle de GridView.

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

Compile y ejecute la aplicación para ver su aspecto. A medida que cambia el tamaño de la ventana, el control GridView se encarga de reorganizar los elementos para adaptarlos mejor al espacio. Con determinados anchos queda gran cantidad de espacio en el lado derecho de la ventana de la aplicación. Es mejor que GridView o su contenido estén centrados. No ocuparemos de esto a continuación.

Sugerencia

Si quiere experimentar, intente establecer las propiedades Background y Margin en distintos valores para ver el efecto de dicho cambio.

Paso 9: Experimentación con el diseño

Es posible que se pregunte si es mejor centrar GridView o su contenido. Primero centre GridView.

  1. Para que sea fácil ver exactamente dónde está GridView en la ventana y lo que sucede cuando experimente con el diseño, establezca la propiedad Background en rojo.

    <GridView x:Name="ImageGridView"
            ...
            Background="Red">
    </GridView>
    
  2. A continuación, establezca la propiedad HorizontalAlignment en Center.

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

    Consulte también Alineación, margen y relleno.

Compile y ejecute el proceso, y experimente con el ajuste del ancho de la ventana. Puede ver que hay una cantidad igual de espacio vacío en cualquier lado del fondo rojo de GridView. Así que ha logrado el objetivo de centrar las imágenes. Pero ahora está más claro que antes que la barra de desplazamiento pertenece a GridView y no a la ventana. Por lo tanto, es necesario volver a cambiar GridView para rellenar la ventana. Hemos demostrado que, en lugar de centrar GridView en la ventana, es necesario centrar las imágenes en GridView.

  1. Por lo tanto, elimine ahora el atributo HorizontalAlignment que agregó en el paso anterior.

Paso 10: Edición de la plantilla del panel de elementos

Los controles de elementos colocan sus contenedores de elementos dentro de lo que se conoce como un panel de elementos. Podemos definir qué tipo de panel se usa y establecer propiedades en este mediante la edición de la plantilla de panel de elementos de GridView. Así que eso es lo que haremos en esta sección.

  1. En MainWindow.xaml, agregue un recurso ItemsPanelTemplate al diccionario de recursos. El panel de elementos es de tipo ItemsWrapGrid y tiene que establecer su propiedad HorizontalAlignment en Center.

    <Grid>
        <Grid.Resources>
        ...
            <ItemsPanelTemplate x:Key="ImageGridView_ItemsPanelTemplate">
                <ItemsWrapGrid Orientation="Horizontal"
                               HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </Grid.Resources>
    
  2. A continuación, use la clave ImageGridView_ItemsPanelTemplate para establecer itemsPanel de GridView.

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

Al compilar y ejecutar este tiempo y experimentar con el ajuste del ancho de la ventana, hay una cantidad igual del fondo rojo de GridView en cualquiera de los lados de las imágenes. Como GridView rellena la ventana, la barra de desplazamiento se alinea perfectamente con el borde de la ventana, justo donde los usuarios esperan.

  1. Ahora que ha terminado de experimentar con el diseño, quite Background="Red" de GridView.

Paso 11: Reemplazo de la imagen de marcador de posición por una foto

Ahora tiene que mover el boceto a un mayor nivel de fidelidad; eso significa que debe reemplazar la imagen de marcador de posición por las imágenes reales y reemplazar el texto del marcador de posición "lorem ipsum" por datos reales. En primer lugar, tiene que ocuparse de las imágenes.

Importante

La técnica que usará para mostrar las fotos en la carpeta Assets\Samples implica actualizar progresivamente los elementos de GridView. Concretamente, es el código de los métodos ImageGridView_ContainerContentChanging y ShowImage del ejemplo de código siguiente, incluido el uso de las propiedades ContainerContentChangingEventArgs.InRecycleQueue y ContainerContentChangingEventArgs.Phase. Para obtener más información, consulta Optimización de la interfaz de usuario de ListView y GridView. En pocas palabras, GridView le informará (por medio de un evento) cuando tenga uno de sus contenedores de elementos listo para mostrar el elemento. A continuación, realice el seguimiento de la fase de su ciclo de vida de actualización en el que se encuentra el contenedor de elementos para poder determinar cuándo está listo para mostrar los datos de la foto.

  1. En MainWindow.xaml.cs, agregue un nuevo método a MainWindow denominado ImageGridView_ContainerContentChanging. Se trata de un método de control de eventos y el evento que controla es ContainerContentChanging. También es necesario proporcionar la implementación del método ShowImage del que depende ImageGridView_ContainerContentChanging. Pegue la directiva using y las dos implementaciones de método en 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. En MainWindow.xaml, registre el controlador de eventos ImageGridView_ContainerContentChanging con el evento ContainerContentChanging de GridView.

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

Paso 12: Reemplazo del texto del marcador de posición por datos reales

En esta sección usará enlaces de datos de un solo uso. Un enlace único es ideal para los datos que no cambian en tiempo de ejecución. Eso significa que los enlaces únicos son de alto rendimiento y fáciles de crear.

  1. En MainWindow.xaml, busque el recurso de plantilla de datos ImageGridView_ItemTemplate. Indique a la plantilla de datos que su trabajo es el de una plantilla para la clase ImageFileInfo (recuerde que es el tipo de elementos que muestra GridView).

  2. Para ello, agregue un valor x:DataType a la plantilla, de la siguiente manera:

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

    Si no está familiarizado con la sintaxis local: que se mostró anteriormente (o con la sintaxis xmlns:local que ya está en la etiqueta Ventana de apertura), consulte Espacios de nombres XAML y asignación de espacios de nombres.

    Ahora que ha establecido un elemento x:DataType, puede usar las expresiones de enlace de datos x:Bind en la plantilla de datos para enlazar las propiedades del tipo de datos especificado (ImageFileInfo, en este caso).

  3. En la plantilla de datos, busque el primer elemento TextBlock (el que tiene el valor Text establecido en ImageTitle). Reemplace el valor Text tal como se muestra a continuación.

    Sugerencia

    Puede copiar y pegar el marcado siguiente, o bien puede usar IntelliSense en Visual Studio. Para ello, seleccione el valor actual que está entre comillas y escriba {. IntelliSense agrega automáticamente la llave de cierre y muestra una lista de finalización de código. Puede desplazarse hacia abajo hasta x:Bind y hacer doble clic. Aun así, puede ser más eficaz escribir x: (tenga en cuenta cómo x:Bind se filtra a continuación a la parte superior de la lista de finalización) y presionar la tecla TAB. Presione la tecla ESPACIO y escriba ImageT (escriba tantos caracteres del nombre de propiedad ImageTitle como sea necesario para que aparezca en la parte superior de la lista de finalización) y presione TAB.

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

    Una expresión x:Bind vincula el valor de una propiedad de interfaz de usuario con el valor de una propiedad data-object. Por supuesto, tiene que establecer primero x:DataType en el tipo de la propiedad data-object para que las herramientas y el tiempo de ejecución sepan qué propiedades están disponibles para enlazar.

    Para obtener más información, consulte la extensión de marcado {x:Bind} y el Enlace de datos en profundidad.

  4. De la misma manera, reemplace los valores de los otros elementos TextBlocks y RatingControl. Este es el resultado:

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

Si compila y ejecuta la aplicación ahora, en lugar de los marcadores de posición verá fotos reales y texto real (además de otros datos). Visual y funcionalmente, esta sencilla aplicación ya está completa. De todas formas, volvamos a usar el enlace de datos.

The finished app.

Paso 13: Enlace de GridView a la colección de imágenes (solamente C#)

Importante

Realice este último paso solo si ha creado un proyecto de C#.

Sugerencia

Verá que hay algunas cosas (normalmente relacionadas con la interfaz de usuario generada dinámicamente) que no puede hacer en el marcado XAML. En general sí puede hacer algo en el marcado, y esto es preferible. Proporciona una separación un poco más clara entre la vista que representa el marcado XAML y el modelo (o el modelo de vista) que representa el código imperativo. Esto tiende a mejorar el flujo de trabajo en las herramientas y los miembros del equipo.

Actualmente usó código imperativo para asociar la propiedad ItemsSource de GridView con la propiedad Images de MainWindow. Pero también puede hacerlo en el marcado.

  1. En la clase MainWindow, elimine (o excluya) la última línea de GetItemsAsync, que establece ItemsSource de ImageGridView en el valor de la propiedad Images.

  2. A continuación, en MainWindow.xaml, busque el elemento GridView denominado ImageGridView y agregue un atributo ItemsSource como este. Puede usar IntelliSense para realizar este cambio si lo desea.

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

El valor de la propiedad Images no cambia en tiempo de ejecución para esta aplicación en particular. De todos modos, dado que Images es de tipo ObservableCollection<T>, el contenido de la colección puede cambiar (es decir, los elementos se pueden agregar o eliminar), y el enlace observará automáticamente los cambios y actualizará la interfaz de usuario.

Conclusión

En este tutorial se ha descrito el proceso de uso de Visual Studio para crear una sencilla aplicación de WinUI 3 que muestra fotos. Esperamos que este tutorial le haya dado la experiencia que necesitaba al trabajar en una aplicación de WinUI 3 con controles, paneles de diseño, enlaces de datos y la optimización de la interfaz de usuario de GridView.

Consulte también

Tutorial: Creación de un visor de fotos sencillo que tiene como destino varias plataformas