为所有备注添加视图和模型

本教程的这一部分将新页面添加到应用,该视图显示以前创建的所有笔记。

多个笔记和导航

当前,笔记视图显示单个笔记。 若要显示所有已保存的笔记,请创建新的视图和模型: AllNotes

  1. “解决方案资源管理器”窗格中,右键单击 Views 文件夹并选择“添加”>新项...
  2. 在“ 添加新项 ”对话框中,选择窗口左侧模板列表中的 WinUI 。 接下来,选择 空白页(WinUI 3) 模板。 为文件 AllNotesPage.xaml 命名,然后按 “添加”。
  3. “解决方案资源管理器”窗格中,右键单击 Models 文件夹并选择“添加”>类...
  4. 为类 AllNotes.cs 命名,然后按 Add

小窍门

可以从 GitHub 存储库下载或查看本教程的代码。 若要查看此步骤中的代码,请参阅此提交: 所有备注视图和模型

编码 AllNotes 模型

新数据模型表示显示多个笔记所需的数据。 在这里,你将从应用的本地存储中获取所有笔记,并创建将在其中显示Note的对象集合AllNotesPage

  1. “解决方案资源管理器” 窗格中,打开 Models\AllNotes.cs 文件。

  2. 将文件中的代码 AllNotes.cs 替换为以下代码:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Threading.Tasks;
    using Windows.Storage;
    
    namespace WinUINotes.Models
    {
        public class AllNotes
        {
            public ObservableCollection<Note> Notes { get; set; } = 
                                        new ObservableCollection<Note>();
    
            public AllNotes()
            {
                LoadNotes();
            }
    
            public async void LoadNotes()
            {
                Notes.Clear();
                // Get the folder where the notes are stored.
                StorageFolder storageFolder = 
                              ApplicationData.Current.LocalFolder;
                await GetFilesInFolderAsync(storageFolder);
            }
    
            private async Task GetFilesInFolderAsync(StorageFolder folder)
            {
                // Each StorageItem can be either a folder or a file.
                IReadOnlyList<IStorageItem> storageItems = 
                                            await folder.GetItemsAsync();
                foreach (IStorageItem item in storageItems)
                {
                    if (item.IsOfType(StorageItemTypes.Folder))
                    {
                        // Recursively get items from subfolders.
                        await GetFilesInFolderAsync((StorageFolder)item);
                    }
                    else if (item.IsOfType(StorageItemTypes.File))
                    {
                        StorageFile file = (StorageFile)item ;
                        Note note = new Note()
                        {
                            Filename = file.Name,
                            Text = await FileIO.ReadTextAsync(file),
                            Date = file.DateCreated.DateTime
                        };
                        Notes.Add(note);
                    }
                }
            }
        }
    }
    

前面的代码声明项的 Note 集合,命名 Notes项,并使用 LoadNotes 该方法从应用的本地存储加载笔记。

Notes 集合使用 ObservableCollection,该集合是一个适用于数据绑定的专用集合。 当列出多个项(如 ItemsView)的控件绑定到一个 ObservableCollection控件时,这两个控件协同工作,以自动使项列表与集合保持同步。 如果将项添加到集合中,控件将自动更新为新项。 如果将项添加到列表中,则更新集合。

在文档中了解详细信息:

现在, AllNotes 模型已准备好为视图提供数据,因此需要创建模型的 AllNotesPage 实例,以便视图可以访问模型。

  1. “解决方案资源管理器” 窗格中,打开 Views\AllNotesPage.xaml.cs 文件。

  2. 在类中 AllNotesPage ,添加此代码以创建 AllNotes 名为 notesModel 的模型:

    public sealed partial class AllNotesPage : Page
    {
        // ↓ Add this. ↓
        private AllNotes notesModel = new AllNotes();
        // ↑ Add this. ↑
    
        public AllNotesPage()
        {
            this.InitializeComponent();
        }
    }
    

设计 AllNotes 页

接下来,需要设计视图以支持 AllNotes 模型。

  1. “解决方案资源管理器” 窗格中,打开 Views\AllNotesPage.xaml 文件。

  2. <Grid> ... </Grid> 元素替换为以下标记:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
        <CommandBar DefaultLabelPosition="Right">
            <AppBarButton Icon="Add" Label="New note"/>
            <CommandBar.Content>
                <TextBlock Text="Quick notes" Margin="16,8" 
                       Style="{ThemeResource SubtitleTextBlockStyle}"/>
            </CommandBar.Content>
        </CommandBar>
    
        <ItemsView ItemsSource="{x:Bind notesModel.Notes}" 
               Grid.Row="1" Padding="16" >
            <ItemsView.Layout>
                <UniformGridLayout MinItemWidth="200"
                               MinColumnSpacing="12"
                               MinRowSpacing="12"
                               ItemsJustification="Start"/>
            </ItemsView.Layout>
        </ItemsView>
    </Grid>
    

前述 XAML 介绍一些新概念:

  • CommandBar 控件包含 AppBarButton。 此按钮有一个 LabelIcon并且受 CommandBar 包含该按钮的影响。 例如,这 CommandBar 会将按钮的标签位置设置为 Right。 命令栏通常显示在应用顶部,以及页面标题。
  • ItemsView 控件显示项的集合,在本例中,绑定到模型Notes的属性。 项目视图通过属性设置 ItemsView.Layout 项目的方式。 在这里,你将使用 UniformGridLayout

创建后 AllNotesPage,需要上次更新 MainWindow.xaml 一次,以便加载它 AllNotesPage 而不是单个 NotePage

  1. “解决方案资源管理器” 窗格中,打开 MainWindow.xaml 文件。

  2. rootFrame更新元素以便指向SourcePageTypeviews.AllNotesPage,如下所示:

    <Frame x:Name="rootFrame" Grid.Row="1"
           SourcePageType="views:AllNotesPage"/>
    

如果现在运行应用,你将看到之前创建的注释已加载到控件中 ItemsView 。 但是,它只是显示为对象的字符串表示形式。 ItemsView不知道应如何显示此项。 在下一部分中更正此问题。

备注应用 UI,其中备注列表显示 Note 类名称,而不是备注内容。

添加数据模板

需要指定 DataTemplate 来告知 ItemsView 数据项的显示方式。 分配给 DataTemplateItemsTemplate 属性的 ItemsView. 对于集合中的每个项,ItemsView.ItemTemplate 将生成声明的 XAML。

  1. “解决方案资源管理器” 窗格中,双击 AllNotesPage.xaml 该条目以在 XAML 编辑器中打开它。

  2. 在映射下方的行中添加此新命名空间映射 local

    xmlns:models="using:WinUINotes.Models"
    
  3. 在开始<Page.Resources>标记后添加元素<Page...>。 这会从Page”属性获取 ResourceDictionary,以便你可以向其添加 XAML 资源。

    <Page
        x:Class="WinUINotes.Views.AllNotesPage"
        ... >
    <!-- ↓ Add this. ↓ -->
    <Page.Resources>
    
    </Page.Resources>
    
  4. 在元素内 <Page.Resources> ,添加 DataTemplate 描述如何显示 Note 项的元素。

    <Page.Resources>
        <!-- ↓ Add this. ↓ -->
        <DataTemplate x:Key="NoteItemTemplate" 
                      x:DataType="models:Note">
            <ItemContainer>
                <Grid Background="LightGray">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="120"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock Text="{x:Bind Text}" Margin="12,8"
                               TextWrapping="Wrap"
                               TextTrimming="WordEllipsis"/>
                    <Border Grid.Row="1" Padding="8,6,0,6"
                            Background="Gray">
                        <TextBlock Text="{x:Bind Date}"
                                   Foreground="White"/>
                    </Border>
                </Grid>
            </ItemContainer>
        </DataTemplate>
        <!-- ↑ Add this. ↑ -->
    </Page.Resources>
    
  5. 在 XAML 中 ItemsView,将 ItemTemplate 属性分配给刚刚创建的数据模板:

    <ItemsView ItemsSource="{x:Bind notesModel.Notes}"
               Grid.Row="1" Margin="24"
               <!-- ↓ Add this. ↓ -->
               ItemTemplate="{StaticResource NoteItemTemplate}">
    
  6. 生成并运行应用。

x:Bind在一个DataTemplate中使用标记扩展时,必须指定x:DataType该标记扩展。DataTemplate 在这种情况下,这是个人Note(因此必须添加 XAML 命名空间引用)。Models 注释的模板使用两 TextBlock 个控件,这些控件绑定到笔记 Text 的属性 DateGrid 元素用于布局并提供背景色。 Border 元素用于日期的背景。 (XAML Border 元素可以提供大纲和背景。

运行应用时,数据模板将应用于项目 Note ,如果你的 Windows 个性化 > 颜色设置使用浅色模式,则如下所示:

备注应用 UI,其中包含备注列表,其中显示了数据模板格式化的笔记内容和日期。

但是,如果你的 Windows 个性化 > 设置使用深色模式,它将如下所示:

具有深色背景但浅灰色笔记模板的备注应用 UI。

这不是应用的预期外观。 之所以发生,是因为笔记的数据模板中有硬编码的颜色值。 默认情况下,WinUI 元素适应用户的深色或浅色首选项。 定义自己的元素(如数据模板)时,需要小心执行相同的作。

在 XAML ResourceDictionary中定义资源时,必须分配一个 x:Key 值来标识资源。 然后,可以使用该x:Key扩展或{StaticResource}标记扩展在 XAML {ThemeResource} 中检索资源。

  • 无论颜色主题是什么,A {StaticResource} 都是相同的,因此它用于诸如或Font设置之类的Style内容。
  • {ThemeResource}基于所选颜色主题的更改,因此它用于ForegroundBackground其他与颜色相关的属性。

WinUI 包括各种内置资源,可用于使应用遵循 Fluent 样式准则,以及辅助功能指南。 你将使用内置主题资源替换数据模板中的硬编码颜色,并应用其他一些资源来匹配 Fluent Design 指南。

  1. 在之前添加的数据模板中,更新此处指示的节以使用内置资源:

    <DataTemplate x:Key="NoteItemTemplate" 
                  x:DataType="models:Note">
    
    <!-- ↓ Update this. ↓ -->
        <ItemContainer CornerRadius="{StaticResource OverlayCornerRadius}">
            <Grid Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
                  BorderThickness="1" 
                  BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
                  CornerRadius="{StaticResource OverlayCornerRadius}">
    <!-- ↑ Update this. ↑ -->
    
                <Grid.RowDefinitions>
                    <RowDefinition Height="120"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBlock Text="{x:Bind Text}" Margin="12,8"
                           TextWrapping="Wrap"
                           TextTrimming="WordEllipsis"/>
    
    <!-- ↓ Update this. ↓ -->
                <Border Grid.Row="1" Padding="8,6,0,6"
                        Background="{ThemeResource SubtleFillColorSecondaryBrush}">
                    <TextBlock Text="{x:Bind Date}"
                        Style="{StaticResource CaptionTextBlockStyle}"
                        Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
    <!-- ↑ Update this. ↑ -->
    
                </Border>
            </Grid>
        </ItemContainer>
    </DataTemplate>
    

现在,当你使用浅色设置运行应用时,它将如下所示:

具有浅色背景和浅色便笺模板的便笺应用 UI。

当你使用深色设置运行应用时,它将如下所示:

具有深色背景和深色笔记模板的备注应用 UI。

在文档中了解详细信息:

小窍门

该 WinUI 3 Gallery 应用是了解不同 WinUI 控件和设计指南的好方法。 若要查看数据模板中使用的主题资源, 请打开 WinUI 3 Gallery 应用以“颜色”指南。 在此处,可以看到资源的外观,并直接从应用复制所需的值。

还可以打开 “版式”页“几何图形”页 ,查看此数据模板中使用的其他内置资源。

WinUI 3 Gallery 应用包含大多数 WinUI 3 控件、特性和功能的交互式示例。 从 Microsoft 应用商店获取应用或在 GitHub 上获取源代码