共用方式為


教學課程:使用 WinUI 3 建立簡單的相片檢視器

注意

如需 WinUI 3 的優點及其他應用程式類型選項的相關信息,請參閱 架構選項概觀。

在本主題中,我們將逐步解說如何在 Visual Studio 中建立新的 WinUI 3 專案;然後建置可顯示相片的簡易應用程式。 我們將會使用控制項、版面配置面板和資料繫結。 我們將撰寫 XAML 標記 (亦即宣告式),以及您選擇的 C# 或 C++ 程式碼 (亦即命令式程序)。 請使用主題標題上方的語言選擇器,選擇 C# 或 C++/WinRT。

提示

本主題中的原始程式碼同時提供 C# 和 C++/WinRT 版本。 如果您是 C++ 開發人員,請參閱 C++/WinRT 文件,以查看更多詳細資訊和概念解說,以瞭解本主題所述程式碼的運作方式。 該文件中的相關主題包含 XAML 控制項;繫結至 C++/WinRT 屬性XAML 項目控制項;繫結至 C++/WinRT 集合,以及Photo Editor C++/WinRT 範例應用程式

步驟 1:安裝 Windows 應用程式 SDK 的工具

若要設定開發計算機,請參閱 開始使用 WinUI。 在本文中,您也會找到建立和啟動 WinUI 3 專案的指示。

重要

您可以在 Windows 應用程式 SDK 發行通道主題中找到版本資訊主題。 每個通道都有版本資訊。 請務必查看這些版本資訊中的任何限制和已知問題,因為在遵循本教學課程和/或執行我們將建置的應用程式時,這些資訊可能會影響結果。

步驟 2:建立新專案

在 Visual Studio 中,從已封裝的空白應用程式 (WinUI 3 in Desktop) 專案範本,選擇建立新的 C# 或 C++ 專案。 將專案命名為 SimplePhotos,並 (以便使資料夾結構符合本教學課程所述的專案) 取消勾選將方案和專案放置於同一個目錄。 您可以將目標設為用戶端作業系統的最新版本 (非預覽版)。

步驟 3:複製資產檔案

我們將建置的應用程式會以資產檔案的形式夾帶影像檔;而這些影像檔便是該應用程式所顯示的相片。 在本節中,您會將這些資產新增到專案中。 但首先,您必須取得檔案的複本。

  1. 因此,請複製 (或下載為 .zip) Windows 應用程式 ADK 範例存放庫 (請參閱 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 資料夾 (該資料夾是專案節點的子系),然後按一下在檔案總管中開啟資料夾。 如此一來,Assets 資料夾便會在檔案總管中開啟。

  2. (在 Assets 資料夾中) 貼上您剛才複製的 Samples 資料夾。

步驟 4:新增 GridView 控制項

我們的應用程式必須顯示相片的資料列和資料行。 也就是影像的格線。 針對這類 UI,主要使用的控制項為清單檢視和方格檢視

  1. 開啟 [MainWindow.xaml]。 目前,其中有 Window 元素,而該元素含有 StackPanel 版面配置面板。 StackPanel 中具有 Button 控制項,其連結至事件處理常式方法。

    任何應用程式的主視窗都代表您在執行應用程式時首先看到的檢視畫面。 在我們將建置的應用程式中,主視窗的工作是從 Samples 資料夾中載入相片,並顯示這些影像的並排檢視,以及各種相關資訊。

  2. StackPanelButton 標記取代為 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.hMainWindow.xaml.cpp,然後刪除 myButton_Click 方法。

您現在可以建置並執行,但此階段將會顯示空白的視窗。 為了讓 GridView 控制項顯示任何內容,我們必須為其提供要顯示的物件集合。 這是我們接下來要開始進行的步驟。

如需我們剛才提及之部分類型的背景資訊,請參閱版面配置面板Windows 應用程式控制項

步驟 5:ImageFileInfo 模型

模型 (就模型、檢視和檢視模型而言) 是一種類別,可在一定程度上代表真實世界的物件或概念 (例如銀行帳戶)。 這是以抽象方法呈現真實世界的事物。 在本節中,我們將在專案中新增名為 ImageFileInfo 的新類別。 ImageFileInfo 將是如相片等影像檔的模型。 本節將帶領我們完成下一個步驟,以便能夠在應用程式的使用者介面 (UI) 中顯示相片。

提示

為了準備好處理以下的程式碼範例,讓我們先來了解可觀察一詞。 可以動態繫結至 XAML 控制項的屬性 (以便在每次屬性值變更時更新 UI) 稱為可觀察屬性。 這個主意是以軟體設計模式為基礎稱為觀察者模式。 在本教學課程所建置的應用程式中,ImageFileInfo 模型的屬性不會變更。 但即便如此,我們也會示範如何藉由實作 INotifyPropertyChanged 介面,使 ImageFileInfo 變為可觀察。

  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. 使用影像填入新集合屬性的程式碼會顯示在下列的 GetItemsAsyncLoadImageInfoAsync 方法中。 也請將 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 類別的任何資訊。 因此,目前最好的作法是顯示集合中每個 ImageFileInfo 物件的 ToString 值。 根據預設,這只是類型的名稱。 在下一節中,我們將建立資料範本,以定義 ImageFileInfo 物件要以何種方式顯示。

提示

我使用了前述的可觀察集合一詞。 在本教學課程所建置的應用程式中,影像的數目不會變更 (如前所述,每個影像的屬性值也都不會變更)。 不過,使用資料繫結將 UI 初始連結到資料仍是方便且良好的作法。 我們接下來就要進行這項步驟。

步驟 7:新增資料範本

首先,讓我們使用類似草圖的預留位置資料範本。 在我們探索完幾個版面配置選項之前,會一直使用該範本。 隨後,我們可以更新資料範本以顯示實際的相片。

提示

這實際上是非常實用的作法。 我們發現,如果 UI 看起來像草圖 (也就是真實感不高),會更令人願意提出靈感及/或進行測試,有時還會涉及相當大幅度的變動。 這是因為我們猜測 (實際上也確實如此) 可以輕鬆嘗試這樣的變動。

另一方面,UI 外觀的完成度越高 (真實感越高),我們就更容易猜測 (同樣地,實際上也確實如此) 目前的外觀是投入大量心力才完成的。 這使得我們不太傾向於提議或嘗試新的想法。

  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 索引鍵。 我們也已使用相同的索引鍵來設定 GridViewItemTemplate。 如 GridView 等項目控制項具有 ItemTemplate 屬性 (就像具有我們先前看到的 ItemsSource 屬性一樣)。 項目範本是一種資料範本;用於顯示集合中的每個項目。

    如需詳細資訊,請參閱項目容器與範本

  2. 現在,我們可以對資料範本進行一些編輯,新增並編輯其中的元素,使範本更加有趣且實用。 我們會將根 Grid 的高度和寬度設為 300,邊界為 8。 然後,我們會新增兩個資料列定義,並將第二個資料列定義的高度設定為 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

因此,本節將著重於設計項目容器的樣式。 為此,我們將為 GridViewItem 建立 Style 資源,然後將其設定為 *GridViewItemContainerStyle。 在樣式中,我們將設定項目容器的 BackgroundMargin 屬性,使其具有灰色背景,且外圍有些許邊界。

  1. MainWindow.xaml 中,新增 Style 資源到我們放入資料範本的同一個 Grid.Resources XML 元素中。

    <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 索引鍵來設定 GridViewItemContainerStyle

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

建置並執行應用程式,看看目前會是什麼樣子。 調整視窗大小時,GridView 控制項會負責重新排列項目,以符合空間大小。 有些寬度會使應用程式視窗右側留下很大的空間。 如果將 GridView 和/或其內容置中,畫面會更美觀。 所以,我們接下來就要進行這個步驟。

提示

如果您想要實驗,請嘗試將 BackgroundMargin setter 設定為不同值,看看會有什麼效果。

步驟 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 索引鍵來設定 GridViewItemsPanel

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

這次在建置並執行時,以及實驗調整視窗寬度時,影像任一側都會有相等的 GridView 紅色背景。 而且因為 GridView 填滿視窗,所以捲軸會與視窗邊緣妥善對齊,這正是使用者所預期的位置。

  1. 現在我們已完成版面配置實驗,請從 GridView 移除 Background="Red"

步驟 11:將預留位置影像取代為相片

現在是時候提高草圖的真實度;這表示要將預留位置影像取代為實際影像,並以實際資料取代「lorem ipsum」樣式的預留位置文字。 讓我們先從影像開始。

重要

我們將用來在 Assets\Samples 資料夾中顯示相片的技巧,涉及到逐步更新 GridView 的項目。 具體來說,這是下列程式碼範例中 ImageGridView_ContainerContentChangingShowImage 方法內的程式碼,包括使用 ContainerContentChangingEventArgs.InRecycleQueueContainerContentChangingEventArgs.Phase 屬性。 如需詳細資訊,請參閱 ListView 與 GridView UI 最佳化。 但簡言之,若其中一個項目容器已準備好顯示項目,GridView 將會告知我們 (透過事件)。 然後,我們將持續追蹤該項目容器進行到更新生命週期的哪個階段,以便判斷它何時會準備好顯示相片資料。

  1. MainWindow.xaml.cs 中,將新的方法加到 MainWindow 中,並命名為 ImageGridView_ContainerContentChanging。 這是一項事件處理方法,而其所處理的事件為 ContainerContentChanging。 我們也需要提供 ImageGridView_ContainerContentChanging 相依之 ShowImage 方法的實作。 請將 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 中,針對 GridViewcontainerContentChanging 事件註冊 ImageGridView_ContainerContentChanging 事件處理常式。

    <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: 語法 (或不熟悉開啟 Window 標籤中已有的 xmlns:local 語法),請參閱 XAML 命名空間與命名空間對應

    既然我們已設定 x:DataType,就可以在資料範本中使用 x:Bind 資料繫結運算式,以繫結至我們指定的資料類型屬性 (在本例中為 imageFileInfo)。

  3. 在資料範本中,尋找第一個 TextBlock 元素 (其 Text 目前設定為 ImageTitle 的元素)。 將其 Text 值取代為如下所示的值。

    提示

    您可以複製並貼上下列標記,也可以在 Visual Studio 中使用 IntelliSense。 若要採取此方式,請選取目前在引號內的值,然後輸入 {。 IntelliSense 會自動新增右大括弧,並顯示程式碼完成清單。 您可以向下捲動至 x:Bind,然後按兩下。 不過輸入 x: 可能更有效率 (請注意,x:Bind 隨後會篩選至完成清單頂端),然後請按下 TAB 鍵。 現在請按下 SPACE 鍵,並輸入 ImageT (請輸入必要數量的屬性名稱 ImageTitle,以使其位於完成清單頂端),然後按下 TAB 鍵。

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

    x:Bind 運算式會將 UI 屬性的值與資料物件屬性的值相連結。 當然,這必須是首次將 x:DataType 設定為該資料物件的類型,工具和執行階段才會知道哪些屬性可供繫結。

    如需更多資訊,請參閱 {x:Bind} 標記延伸深入了解資料繫結

  4. 以相同方式,取代其他 TextBlockRatingControl 的值。 結果如下︰

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

如果現在建置並執行應用程式,您會看到實際的相片和文字 (和其他資料),而非預留位置。 在外觀和功能上,這個簡單的小應用程式現已完成。 但這個程式碼還需要最後一點的資料繫結。

已完成的應用程式。

步驟 13:將 GridView 繫結至 Images 集合 (僅限 C#)

重要

只有在建立 C# 專案時,才需要執行這最後一個步驟。

提示

您會發現在 XAML 標記中,有些操作無法執行 (通常與動態產生的 UI 有關)。 但一般而言,如果有可以在標記中執行的操作,那就是更好的操作。 它可讓你稍微更明確地區別 XAML 標記所代表的檢視,以及命令式程式碼所代表的模型 (或 檢視模型)。 這通常會改善工具和小組成員之間的工作流程。

我們目前使用命令式程式碼,將 GridViewItemsSource 屬性與 mainWindowImages 屬性建立關聯。 但我們可以改為在標記中建立關聯。

  1. MainWindow 類別中,刪除 (或註解刪除) GetItemsAsync 的最後一行,這會將 ImageGridViewItemsSource 設定為 Images 屬性的值。

  2. 然後在 MainWindow.xaml 中,尋找名為 ImageGridViewGridView,並新增如下所示的 ItemsSource 屬性。 您可以選擇使用 IntelliSense 來進行這項變更。

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

Images 屬性值不會在此特定應用程式的執行階段變更。 不過,由於 Images 的類型為 ObservableCollection<T>,因此集合的內容可能會變更 (亦即可以新增或刪除元素),而且繫結會自動注意到變更並更新 UI。

結論

在本教學課程中,我們逐步解說了如何使用 Visual Studio 來建置可顯示相片的簡易 WinUI 3 應用程式。 希望本教學課程讓您有經驗在 WinUI 3 應用程式中處理控制項、版面配置面板、資料繫結和 GridView UI 最佳化。

另請參閱

教學課程:建置以多個平台為目標的簡單相片檢視器