Поделиться через


Руководство. Создание простого средства просмотра фотографий с помощью WinUI 3

Примечание.

Сведения о преимуществах WinUI 3, а также о других параметрах типа приложения см. в разделе "Обзор параметров платформы".

В этом разделе мы рассмотрим процесс создания проекта WinUI 3 в Visual Studio, а также сборки простого приложения для отображения фотографий. Мы будем использовать элементы управления, панели макета и привязку данных. И мы будем писать как разметку XAML (которая является декларативной), так и ваш выбор кода C# или C++ (которые являются императивными или процедурными). Используйте средство выбора языка над заголовком раздела, чтобы выбрать C# или C++/WinRT.

Совет

Исходный код в этом разделе представлен как в C#, так и в C++/WinRT. Если вы являетесь разработчиком C++, дополнительные сведения и основные понятия, объясняющие, как работает код, который мы отображаем здесь, см. в документации по C++/WinRT . К соответствующим темам относятся элементы управления XAML; привязка к свойству C++/WinRT, элементам управления элементам XAML; привязка к коллекции C++/WinRT и примеру приложения "Редактор фотографий C++/WinRT".

Шаг 1. Установка средств для пакета SDK для приложений Windows

Сведения о настройке компьютера разработки см. в статье "Начало работы с WinUI". В этой статье вы также найдете инструкции по созданию и запуску проекта WinUI 3.

Внимание

Среди разделов с заметками о выпуске вы найдете раздел Каналы выпуска Windows App SDK. В нем представлены заметки о выпуске для каждого канала. Обязательно проверьте ограничения и известные проблемы в этих заметках о выпуске, так как они могут повлиять на результаты выполнения инструкций из этого руководства и (или) работу создаваемого приложения.

Шаг 2. Создание проекта

В Visual Studio создайте новый проект C# или C++ из шаблона проекта "Пустое приложение" (WinUI 3 в классическом приложении). Укажите для проекта имя SimplePhotos и (чтобы структура папок соответствовала описанной в этом руководстве) снимите флажок Поместить решение и проект в одном каталоге. В качестве целевой версии вы можете выбрать последний выпуск (не предварительную версию) операционной системы клиента.

Шаг 3. Копирование файлов ресурсов

Приложение, которое мы будем создавать, содержит файлы изображений в виде файлов ресурсов. Это фотографии, которые оно отображает. В этом разделе показано, как добавить эти ресурсы в проект. Но сначала необходимо получить копию файлов.

  1. Поэтому клонируйте (или скачайте в виде архива .zip) репозиторий примеров Windows App SDK (см. раздел WindowsAppSDK-Samples). Выполнив это, вы найдете файлы ресурсов, которые мы будем использовать в папке (используйте эту папку \WindowsAppSDK-Samples\Samples\PhotoEditor\cs-winui\Assets\Samples для проекта C# и C++/WinRT). Если вы хотите просмотреть эти файлы в репозитории в Интернете, вы можете посетить WindowsAppSDK-Samples/Samples/PhotoEditor/cs-winui/Assets/Samples/.

  2. В проводнике выберите папку Samples и скопируйте ее в буфер обмена.

  1. Перейдите к Обозреватель решений в Visual Studio. Щелкните правой кнопкой мыши папку "Ресурсы" (она является дочерним элементом узла проекта) и щелкните "Открыть папку" в проводник. Папка Assets откроется в проводнике.

  2. Вставьте (в папку Assets) только что скопированную папку Samples.

Шаг 4. Добавление элемента управления GridView

Наше приложение должно отображать строки и столбцы фотографий, то есть сетку изображений. Для такого пользовательского интерфейса основными элементами управления будут представление списка и представление сетки.

  1. Открыть MainWindow.xaml. На данный момент этот файл содержит элемент Window, в котором есть панель макета StackPanel. В StackPanel присутствует элемент управления Button, связанный с методом обработчика событий.

    Главное окно любого приложения — это представление, которое отображается первым при запуске приложения. В приложении, которое мы создадим, задачей главного окна является загрузка фотографии из папки Samples, а также отображение этих изображений в виде плиток вместе с различными сведениями о них.

  2. Замените разметку StackPanel и Button панелью сетки Grid и элементом управления GridView, как показано в листинге ниже.

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

    Совет

    x:Name определяет элемент XAML, чтобы на него можно было добавить ссылку в другом месте кода XAML и кода программной части.

  3. C#. Откройте MainWindow.xaml.cs и удалите метод myButton_Click.

  4. C++/WinRT. Откройте MainWindow.xaml.h и MainWindow.xaml.cppудалите метод myButton_Click .

Теперь можно выполнить сборку и запуск, но на этом этапе окно будет пустым. Чтобы элемент управления GridView отображал какие-либо объекты, необходимо предоставить ему коллекцию объектов. Мы приступим к этой задаче в следующем разделе.

Дополнительные сведения о некоторых типах, которые мы только что упомянули, см. в разделах Панели макета и Элементы управления приложений для Windows.

Шаг 5. Модель ImageFileInfo

Модель (имеются в виду модели, представления и модели представлений) — это класс, который в некоторой степени представляет реальный объект или понятие (например, банковский счет). То есть это абстракция этой реальной вещи. В этом разделе мы добавим в проект новый класс ImageFileInfo. ImageFileInfo будет представлять собой модель файла изображения, например фотографии. В этом разделе мы приблизимся на один шаг к отображению фотографий в пользовательском интерфейсе приложения.

Совет

При подготовке к работе с приведенным ниже примером кода давайте введем термин наблюдаемый. Свойство, которое может быть динамически привязано к элементу управления XAML (чтобы пользовательский интерфейс обновлялся каждый раз при изменении значения свойства), называется наблюдаемым. Эта идея основана на шаблоне проектирования программного обеспечения, известном как шаблон наблюдателя. В приложении, которое мы создадим в этом руководстве, свойства нашей модели ImageFileInfo не будут изменяться. Но мы все равно покажем, как сделать модель ImageFileInfo наблюдаемой посредством реализации в ней интерфейса INotifyPropertyChanged.

  1. Щелкните правой кнопкой мыши узел проекта (SimplePhotos) и нажмите кнопку "Добавить>новый элемент...". В разделе "Код элементов>C#" выберите класс. Задайте имя ImageFileInfo.cs и нажмите кнопку Добавить.

  2. Замените содержимое ImageFileInfo.cs кодом из листинга ниже.

    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. Сохраните и закройте файл ImageFileInfo.cs.

Шаг 6. Определение и заполнение свойства для коллекции изображений

В этом разделе мы добавим новое свойство в класс MainWindow. Свойство (с именем Images) будет представлять собой класс коллекции, содержащей изображения, которые нужно отобразить.

  1. Определите свойство в MainWindow.xaml.cs следующим образом:

    ...
    using System.Collections.ObjectModel;
    ...
    namespace SimplePhotos
    {
        public sealed partial class MainWindow : Window
        {
            public ObservableCollection<ImageFileInfo> Images { get; } = 
                new ObservableCollection<ImageFileInfo>();
            ...
        }
    }
    
  2. Код для заполнения нового свойства коллекции изображениями показан в методах GetItemsAsync и LoadImageInfoAsync ниже. Вставьте директивы using и две реализации методов в MainWindow.xaml.cs. Эти методы являются членами класса MainWindow , поэтому вставьте их внутрь так же, как и в свойстве Images выше.

    ...
    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. Последняя задача, которую нам необходимо выполнить в этом разделе, — обновить конструктор MainWindow для вызова GetItemsAsync.

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

При желании вы можете выполнить сборку и запуск сейчас (чтобы проверить, правильно ли выполнены действия), но на этом этапе в окне не отобразится много данных. Это потому что мы реализовали только запрос к GridView на обработку коллекции объектов с типом ImageFileInfo, но GridView пока что не знает, как это сделать.

Помните, что свойство Images является наблюдаемой коллекцией объектов ImageFileInfo. Последняя строка GetItemsAsync сообщает GridView (который называется ImageGridView), что источником его элементов (ItemsSource) является свойство Images. Таким образом, GridView должен отобразить эти элементы.

Но мы пока что ничего не сообщили GridView о классе ImageFileInfo. Поэтому на этом этапе он может только отобразить значение ToString каждого объекта ImageFileInfo в коллекции. По умолчанию это просто имя типа. В следующем разделе мы создадим шаблон данных, чтобы определить способ отображения объекта ImageFileInfo.

Совет

Выше мы использовали термин наблюдаемая коллекция. В приложении, которое мы создаем в этом руководстве, количество изображений не меняется и, как мы уже говорили, значения свойств каждого изображения, также не меняются. Однако будет удобно и рекомендуется использовать привязку к данным, чтобы сначала подключить пользовательский интерфейс к данным. Это мы и сделаем.

Шаг 7. Добавление шаблона данных

Для начала мы применим замещающий шаблон данных, напоминающий эскиз. Мы будем использовать его, пока мы не разберем некоторые варианты шаблонов. После этого мы сможем обновить шаблон данных для отображения фактических фотографий.

Совет

Этот подход является весьма практичным. Мы заметили, что если пользовательский интерфейс выглядит как эскиз (другими словами, с низкой точностью), то люди больше готовы предложить и (или) протестировать легко реализуемые идеи в нем, иногда с внесением существенных изменений. Мы предполагаем (и вполне обоснованно), это связанно с тем, что тестирование таких изменений не потребует больших затрат.

С другой стороны, чем более готовым выглядит пользовательский интерфейс (чем выше точность), тем больше, как мы считаем (опять же, обоснованно), ресурсов потрачено на его внешний вид. В связи с этим, мы менее склонны предложить или опробовать новые идеи.

  1. Откройте MainWindow.xaml и измените содержимое Window таким образом, чтобы оно выглядело следующим образом:

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

    В корень макета мы добавили простой ресурс DataTemplate и предоставили ему ключ ImageGridView_ItemTemplate. Этот же ключ мы использовали для указания ItemTemplate элемента управления GridView. Элементы управления элементами, такие как GridView, имеют свойство ItemTemplate (как и свойство ItemsSource, которое мы видели ранее). Шаблон элемента — это шаблон данных. Они используется для отображения каждого элемента в коллекции.

    Дополнительные сведения см. в статье Контейнеры и шаблоны элементов.

  2. Теперь мы можем внести некоторые изменения в шаблон данных: добавить и изменить элементы в нем, чтобы сделать шаблон более интересным и полезным. Мы зададим для свойств Height и Width элемента Grid значение 300, а для свойства Margin — 8. Затем мы добавим два определения строк и зададим для свойства Height второго определения строки значение Auto.

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

    Дополнительные сведения см. в статье Выравнивание, поле, отбивка.

  3. Нам нужно, чтобы шаблон данных отображал изображение, имя, тип файла, размеры и оценку каждой фотографии. Поэтому мы добавим, соответственно, элемент управления Image, несколько элементов управления TextBlock и элемент управления RatingControl. Мы разместим текст на панелях макета StackPanel. На первых этапах элемент управления Image будет отображать в качестве заполнителя логотип Microsoft Store в виде эскиза проекта.

  4. После внесения всех изменений шаблон данных должен выглядеть так:

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

Теперь выполните сборку проекта и запустите приложение, чтобы просмотреть элемент управления GridView с только что созданным шаблоном элемента. После этого мы посмотрим, как размещены элементы. Мы изменим некоторые кисти и добавим пространство между элементами.

Шаблон элемента заполнителя.

Шаг 8. Изменение стиля контейнера элементов

С элементами управления элементами, такими как GridView, связано еще одно понятие — контейнер элементов. Контейнер элементов — это элемент управления контентом, который отображает элемент в качестве значения его свойства Content. Элемент управления элементами создает столько контейнеров элементов, сколько требуется для отображения элементов, видимых на экране в любой момент времени.

Так как это элемент управления, контейнер элементов имеет стиль и шаблон элемента управления. Его стиль и шаблон элемента управления определяют, как контейнер элементов выглядит в различных состояниях (например, при выделении наведении указателя или фокусировке). Как мы видели ранее, шаблон элемента (который является шаблоном данных) определяет вид самого элемента.

Для GridView используется тип контейнера элементов GridViewItem.

Поэтому в этом разделе мы сосредоточимся на создании стиля контейнера элементов. Для этого мы создадим ресурс Style для GridViewItem, а затем настроим его в качестве ItemContainerStyle элемента управления *GridView. В блоке стиля мы укажем свойства Background и Margin контейнера элементов, чтобы настроить для контейнера серый фон и поля вокруг него.

  1. В файле MainWindow.xaml добавьте новый ресурс Style для того же XML-элемента Grid.Resources, в который мы помещаем шаблон данных.

    <Grid>
        <Grid.Resources>
        ...
            <Style x:Key="ImageGridView_ItemContainerStyle"
                TargetType="GridViewItem">
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Margin" Value="8"/>
            </Style>
        </Grid.Resources>
    
  2. Затем мы с помощью ключа ImageGridView_ItemContainerStyle задаем ItemContainerStyle элемента управления GridView.

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

Выполните сборку и запуск приложения, а затем посмотрите, как оно выглядит на этом этапе. При изменении размера окна элемент управления GridView выполняет переупорядочение элементов для их наиболее оптимального размещения. Но при некоторых значениях ширины в правой части окна приложения остается много пространства. Приложение выглядело бы лучше, если бы GridView и (или) его содержимое располагались по центру. Мы позаботимся об этом в следующей части.

Совет

Если вы хотите поэкспериментировать, попробуйте изменять значения методов задания Background и Margin и посмотрите на результат.

Шаг 9. Экспериментирование с макетом

Вы можете оказаться перед выбором, что лучше: разместить по центру сам элемент управления GridView или его содержимое. Сначала попробуем разместить по центру сам элемент управления GridView.

  1. Чтобы было проще просмотреть расположение GridView в окне и результаты экспериментирования с макетом, мы присвоим свойству Background красный цвет.

    <GridView x:Name="ImageGridView"
            ...
            Background="Red">
    </GridView>
    
  2. Теперь мы зададим для свойства HorizontalAlignment значение Center.

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

    См. также статью Выравнивание, поле и отбивка.

Выполните сборку и запуск, а затем поэкспериментируйте с настройкой ширины окна. Вы увидите, что на красном фоне GridView размер пустого пространства одинаковый с каждой стороны. Мы достигли своей цели — разместили изображения по центру. Но теперь стало ясно, что полоса прокрутки относится к элементу GridView, а не к окну. Поэтому нам нужно вернуть GridView обратно к заполнению окна. Мы показали, что вместо размещения GridView по центру в окне нам нужно разместить по центру изображения в GridView.

  1. Теперь удалите атрибут HorizontalAlignment, добавленный на предыдущем шаге.

Шаг 10. Изменение шаблона панели элементов

Элементы управления элементов размещают контейнеры элементов внутри так называемой панели элементов. Мы можем определить используемый тип панели и задать ее свойства, изменив шаблон панели элементов GridView. Именно этим мы и займемся в этом разделе.

  1. В файле MainWindow.xaml добавьте ресурс ItemsPanelTemplate в наш словарь ресурсов. Панель элементов имеет тип ItemsWrapGrid, и мы зададим для свойства HorizontalAlignment значение Center.

    <Grid>
        <Grid.Resources>
        ...
            <ItemsPanelTemplate x:Key="ImageGridView_ItemsPanelTemplate">
                <ItemsWrapGrid Orientation="Horizontal"
                               HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </Grid.Resources>
    
  2. Затем с помощью ключа ImageGridView_ItemsPanelTemplate мы укажем ItemsPanel элемента GridView.

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

В этот раз при сборке и запуске, а также экспериментировании с настройкой ширины окна размер красного фона GridView будет равным по обе стороны изображений. Поскольку GridView заполняет окно, полоса прокрутки правильно расположена по краю окна, где пользователи и ожидают ее увидеть.

  1. Теперь, когда мы закончили экспериментировать с макетом, удалите Background="Red" из GridView.

Шаг 11. Замена заполнителя фотографией

Теперь пришло время переместить наш эскиз на более высокий уровень точности. Это означает, что нужно заменить замещающее изображение реальными изображениями и заменить замещающий текст lorem ipsum реальными данными. Начнем с изображений.

Внимание

Метод, который мы будем использовать для отображения фотографий из папки Assets\Samples, предусматривает последовательное обновление элементов GridView. В частности, это код в методах ImageGridView_ContainerContentChanging и ShowImage в приведенном ниже примере кода, включая использование свойств ContainerContentChangingEventArgs.InRecycleQueue и ContainerContentChangingEventArgs.Phase. См. сведения о том, как оптимизировать пользовательский интерфейс ListView и GridView. Если коротко, то GridView сообщит нам (посредством события), когда один из его контейнеров элементов будет готов к отображению элемента. После этого мы будем отслеживать, на каком этапе жизненного цикла обновления находится контейнер элементов, чтобы определить, когда он будет готов к отображению данных фотографии.

  1. В файле MainWindow.xaml.cs добавьте новый метод с именем ImageGridView_ContainerContentChanging в MainWindow. Это метод обработки событий. Он обрабатывает событие ContainerContentChanging. Необходимо также предоставить реализацию метода ShowImage, от которого зависит ImageGridView_ContainerContentChanging. Вставьте директиву using и две реализации методов в 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. Затем в MainWindow.xaml зарегистрируйте обработчик событий ImageGridView_ContainerContentChanging с событием ContainerContentChanging элемента GridView.

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

Шаг 12. Замена замещающего текста реальными данными

В этом разделе мы будем использовать однократные привязки данных. Однократная привязка отлично подходит для данных, которые не изменяются во время выполнения. Однократные привязки отличаются высокой производительностью и удобством создания.

  1. В MainWindow.xaml найдите ресурс шаблона данных ImageGridView_ItemTemplate. Мы укажем шаблону данных, что он должен выполнять роль шаблона для класса ImageFileInfo, который, как вы помните, представляет тип элементов, отображаемых GridView.

  2. Для этого добавьте значение x:DataType в шаблон следующим образом:

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

    Если вы не знакомы с приведенным выше синтаксисом local: (или с синтаксисом xmlns:local, который присутствует в открывающем теге Window), ознакомьтесь со статьей Пространства имен XAML и их сопоставление.

    Теперь, когда мы задали значение x:DataType, можно использовать выражения привязки данных x:Bind в шаблоне данных, чтобы создать привязки к свойствам указанного типа данных (в нашем случае — ImageFileInfo).

  3. В шаблоне данных найдите первый элемент TextBlock (в этом элементе для Text указано ImageTitle). Замените его значение Text, как показано ниже.

    Совет

    Вы можете скопировать и вставить приведенную ниже разметку или использовать IntelliSense в Visual Studio. Для этого выберите текущее значение, которое указано в кавычках, и введите {. IntelliSense автоматически добавляет закрывающую скобку и отображает список для завершения кода. Можно прокрутить вниз до элемента x:Bind и дважды щелкнуть его. Но это может быть более эффективным для ввода x: (обратите внимание, как x:Bind затем фильтруется в верхней части списка завершения) и нажимайте клавишу TAB. Теперь нажмите клавишу ПРОБЕЛ и укажите ImageT (введите как можно большую часть имени свойства ImageTitle, чтобы оно отобразилось вверху списка завершения), а затем нажмите клавишу TAB.

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

    Выражение x:Bind связывает значение свойства пользовательского интерфейса со значением свойства data-object. Конечно, сначала необходимо задать в x:DataType тип этого data-object, чтобы средства и среда выполнения знали, какие свойства доступны для привязки.

    Дополнительные сведения см. в статьях Расширение разметки {x:Bind} и Подробно о привязке данных.

  4. Аналогичным образом замените значения других объектов TextBlock и RatingControl. Ниже приведен результат:

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

Если выполнить сборку и запустить приложение на этом этапе, вместо заполнителей вы увидите реальные фотографии и реальный текст (и другие данные). Визуально и функционально это простое небольшое приложение готово. Но в качестве заключительной части давайте выполним еще одну небольшую привязку данных.

Готовое приложение.

Шаг 13. Привязка GridView к коллекции изображений (только C#)

Внимание

Выполните этот последний шаг, только если вы создали проект C#.

Совет

Вы обнаружите, что в разметке XAML нельзя выполнить некоторые действия (обычно связанные с динамически создаваемым пользовательским интерфейсом). Но в целом, предпочтительным будет действие, которое можно выполнить в разметке. Это дает более четкое разделение между представлением, которое представляет разметка XAML, и моделью (или моделью представления), которую представляет императивный код. Это также улучшает рабочий процесс в инструментах и между участниками команды.

В настоящее время для связывания свойства ItemsSource элемента GridView со свойством Images элемента MainWindow мы используем императивный код. Но мы можем сделать это и в разметке.

  1. В классе MainWindow удалите (или закомментируйте) последнюю строку GetItemsAsync, которая задает ItemsSource ImageGridView значения свойства Images.

  2. А затем в файле MainWindow.xaml найдите элемент GridView с именем ImageGridView и добавьте атрибут ItemsSource, как показано ниже. При желании вы можете внести это изменение, используя IntelliSense.

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

Для этого конкретного приложения значение свойства Images не изменяется во время выполнения. Однако поскольку Images имеет тип ObservableCollection<T>, содержимое коллекции может измениться (то есть элементы могут быть добавлены или удалены). При этом привязка автоматически заметит изменения и обновит пользовательский интерфейс.

Заключение

В этом руководстве мы рассмотрели, как с помощью Visual Studio создать простое приложение WinUI 3 для отображения фотографий. Надеемся, что это руководство помогло вам получить навыки работы в приложении WinUI 3 с элементами управления, панелями макета, привязкой данных и оптимизацией пользовательского интерфейса GridView.

См. также

Руководство. Создание простого средства просмотра фотографий, предназначенных для нескольких платформ