本教程的这一部分将新页面添加到应用,该视图显示以前创建的所有笔记。
多个笔记和导航
当前,笔记视图显示单个笔记。 若要显示所有已保存的笔记,请创建新的视图和模型: AllNotes。
- 在“解决方案资源管理器”窗格中,右键单击 Views 文件夹并选择“添加”>新项...。
- 在“ 添加新项 ”对话框中,选择窗口左侧模板列表中的 WinUI 。 接下来,选择 空白页(WinUI 3) 模板。 为文件 AllNotesPage.xaml 命名,然后按 “添加”。
- 在“解决方案资源管理器”窗格中,右键单击 Models 文件夹并选择“添加”>类...。
- 为类 AllNotes.cs 命名,然后按 Add。
小窍门
可以从 GitHub 存储库下载或查看本教程的代码。 若要查看此步骤中的代码,请参阅此提交: 所有备注视图和模型。
编码 AllNotes 模型
新数据模型表示显示多个笔记所需的数据。 在这里,你将从应用的本地存储中获取所有笔记,并创建将在其中显示Note的对象集合AllNotesPage。
在 “解决方案资源管理器” 窗格中,打开 Models\AllNotes.cs 文件。
将文件中的代码 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 实例,以便视图可以访问模型。
在 “解决方案资源管理器” 窗格中,打开 Views\AllNotesPage.xaml.cs 文件。
在类中
AllNotesPage,添加此代码以创建AllNotes名为 notesModel 的模型:public sealed partial class AllNotesPage : Page { // ↓ Add this. ↓ private AllNotes notesModel = new AllNotes(); // ↑ Add this. ↑ public AllNotesPage() { this.InitializeComponent(); } }
设计 AllNotes 页
接下来,需要设计视图以支持 AllNotes 模型。
在 “解决方案资源管理器” 窗格中,打开 Views\AllNotesPage.xaml 文件。
将
<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。 此按钮有一个
Label,Icon并且受CommandBar包含该按钮的影响。 例如,这CommandBar会将按钮的标签位置设置为Right。 命令栏通常显示在应用顶部,以及页面标题。 -
ItemsView 控件显示项的集合,在本例中,绑定到模型
Notes的属性。 项目视图通过属性设置ItemsView.Layout项目的方式。 在这里,你将使用 UniformGridLayout。
创建后 AllNotesPage,需要上次更新 MainWindow.xaml 一次,以便加载它 AllNotesPage 而不是单个 NotePage。
在 “解决方案资源管理器” 窗格中,打开 MainWindow.xaml 文件。
rootFrame更新元素以便指向SourcePageTypeviews.AllNotesPage,如下所示:<Frame x:Name="rootFrame" Grid.Row="1" SourcePageType="views:AllNotesPage"/>
如果现在运行应用,你将看到之前创建的注释已加载到控件中 ItemsView 。 但是,它只是显示为对象的字符串表示形式。
ItemsView不知道应如何显示此项。 在下一部分中更正此问题。
添加数据模板
需要指定 DataTemplate 来告知 ItemsView 数据项的显示方式。 分配给 DataTemplateItemsTemplate 属性的 ItemsView. 对于集合中的每个项,ItemsView.ItemTemplate 将生成声明的 XAML。
在 “解决方案资源管理器” 窗格中,双击 AllNotesPage.xaml 该条目以在 XAML 编辑器中打开它。
在映射下方的行中添加此新命名空间映射
local:xmlns:models="using:WinUINotes.Models"在开始
<Page.Resources>标记后添加元素<Page...>。 这会从“Page”属性获取 ResourceDictionary,以便你可以向其添加 XAML 资源。<Page x:Class="WinUINotes.Views.AllNotesPage" ... > <!-- ↓ Add this. ↓ --> <Page.Resources> </Page.Resources>在元素内
<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>在 XAML 中
ItemsView,将ItemTemplate属性分配给刚刚创建的数据模板:<ItemsView ItemsSource="{x:Bind notesModel.Notes}" Grid.Row="1" Margin="24" <!-- ↓ Add this. ↓ --> ItemTemplate="{StaticResource NoteItemTemplate}">生成并运行应用。
x:Bind在一个DataTemplate中使用标记扩展时,必须指定x:DataType该标记扩展。DataTemplate 在这种情况下,这是个人Note(因此必须添加 XAML 命名空间引用)。Models 注释的模板使用两 TextBlock 个控件,这些控件绑定到笔记 Text 的属性 Date 。
Grid 元素用于布局并提供背景色。
Border 元素用于日期的背景。 (XAML Border 元素可以提供大纲和背景。
运行应用时,数据模板将应用于项目 Note ,如果你的 Windows 个性化 > 颜色设置使用浅色模式,则如下所示:
但是,如果你的 Windows 个性化 > 设置使用深色模式,它将如下所示:
这不是应用的预期外观。 之所以发生,是因为笔记的数据模板中有硬编码的颜色值。 默认情况下,WinUI 元素适应用户的深色或浅色首选项。 定义自己的元素(如数据模板)时,需要小心执行相同的作。
在 XAML ResourceDictionary中定义资源时,必须分配一个 x:Key 值来标识资源。 然后,可以使用该x:Key扩展或{StaticResource}标记扩展在 XAML {ThemeResource} 中检索资源。
- 无论颜色主题是什么,A
{StaticResource}都是相同的,因此它用于诸如或Font设置之类的Style内容。 -
{ThemeResource}基于所选颜色主题的更改,因此它用于ForegroundBackground其他与颜色相关的属性。
WinUI 包括各种内置资源,可用于使应用遵循 Fluent 样式准则,以及辅助功能指南。 你将使用内置主题资源替换数据模板中的硬编码颜色,并应用其他一些资源来匹配 Fluent Design 指南。
在之前添加的数据模板中,更新此处指示的节以使用内置资源:
<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>
现在,当你使用浅色设置运行应用时,它将如下所示:
当你使用深色设置运行应用时,它将如下所示:
在文档中了解详细信息:
小窍门
该 WinUI 3 Gallery 应用是了解不同 WinUI 控件和设计指南的好方法。 若要查看数据模板中使用的主题资源, 请打开 WinUI 3 Gallery 应用以“颜色”指南。 在此处,可以看到资源的外观,并直接从应用复制所需的值。
该 WinUI 3 Gallery 应用包含大多数 WinUI 3 控件、特性和功能的交互式示例。 从 Microsoft 应用商店获取应用或在 GitHub 上获取源代码