现在,你将创建一个页面,允许用户编辑笔记,然后编写代码以保存或删除笔记。
小窍门
可以从 GitHub 存储库下载或查看本教程的代码。 若要查看此步骤中的代码,请参阅此提交: 备注页 - 初始。
首先,将新页面添加至项目:
在 Visual Studio 的解决方案资源管理器 窗格中,右键单击 WinUINotes 项目 >“添加新>项...”。
在“ 添加新项 ”对话框中,选择窗口左侧模板列表中的 WinUI 。 接下来,选择 空白页(WinUI 3) 模板。 将文件 NotePage.xaml命名,然后选择“ 添加”。
该文件 NotePage.xaml 将在新选项卡中打开,其中显示表示页面 UI 的所有 XAML 标记。 将
<Grid> ... </Grid>XAML 中的元素替换为以下标记:<Grid Padding="16" RowSpacing="8"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="400"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBox x:Name="NoteEditor" AcceptsReturn="True" TextWrapping="Wrap" PlaceholderText="Enter your note" Header="New note" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="400" Grid.Column="1"/> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="4" Grid.Row="1" Grid.Column="1"> <Button Content="Save" Style="{StaticResource AccentButtonStyle}"/> <Button Content="Delete"/> </StackPanel> </Grid>通过按 Ctrl + S、单击工具栏中的“保存”图标或选择菜单“”来保存>NotePage.xaml。
如果立即运行应用,则不会看到刚刚创建的备注页。 这是因为你仍然需要将其设置为控件的内容
FrameMainWindow。打开MainWindow.xaml并设置为
NotePage源Frame,如下所示:<Frame x:Name="rootFrame" Grid.Row="1" SourcePageType="local:NotePage"/>现在,当你运行应用时,该
Frame应用将加载一个实例NotePage并将其显示给用户。
重要
XAML 命名空间 (xmlns) 映射 是与 C# using 语句对应的 XAML 映射。
local: 是应用项目的 XAML 页面内映射的前缀(xmlns:local="using:WinUINotes")。 它映射到引用创建的同一命名空间,以包含 x:Class 所有 XAML 文件的属性和代码,包括 App.xaml。 只要在此同一命名空间中定义要在 XAML 中使用的任何自定义类,就可以使用 local: 前缀来引用 XAML 中的自定义类型。
让我们将页面上 XAML 控件的关键部分细分一下:
Grid.RowDefinitions 和 Grid.ColumnDefinitions 定义一个网格,其中包含 2 行和 3 列(放置在标题栏下方)。
- 底部行自动调整
Auto大小以适应其内容(两个按钮)。 顶部行使用所有剩余的垂直空间(*)。 - 中间列宽度为
400epx,是注释编辑器所在的位置。 两侧的列为空,并拆分它们之间的所有剩余水平空间(*)。
注释
由于缩放系统的工作原理,设计 XAML 应用时,需要以有效像素而不是实际物理像素进行设计。 有效像素(epx)是一个虚拟度量单位,用于表达布局尺寸和间距,与屏幕密度无关。
- 底部行自动调整
<TextBox x:Name="NoteEditor" ... > ... </TextBox>是为多行文本输入配置的文本输入控件(TextBox),位于 (Grid) 的Grid.Column="1"顶部中心单元格中。 行索引和列索引基于 0,默认情况下,控件放置在父Grid级的第 0 行和第 0 列中。 因此,这相当于指定第 0 行,第 1 列。<StackPanel Orientation="Horizontal" ... > ... </StackPanel>定义布局控件(StackPanel),该控件可垂直(默认)或水平堆叠其子级。 它放置在 (Grid) 的Grid.Row="1" Grid.Column="1"底部中心单元格中。注释
Grid.Row="1" Grid.Column="1"是 XAML 附加属性的示例。 附加属性允许一个 XAML 对象设置属于其他 XAML 对象的属性。 通常情况下,子元素可以使用附加属性来告知其父元素如何在 UI 中呈现它们。两
<Button>个控件位于水平排列中<StackPanel>。 你将添加代码以处理下一部分中按钮的 Click 事件。
在文档中了解详细信息:
加载并保存笔记
打开 NotePage.xaml.cs 代码隐藏文件。 添加新的 XAML 文件时,代码隐藏包含构造函数中的单个行,即对 InitializeComponent 方法的调用:
namespace WinUINotes
{
public sealed partial class NotePage : Page
{
public NotePage()
{
this.InitializeComponent();
}
}
}
InitializeComponent 方法会读取 XAML 标记并初始化标记定义的所有对象。 对象在其父子关系中连接,代码中定义的事件处理程序将附加到 XAML 中设置的事件。
现在,你要将代码添加到 NotePage.xaml.cs 代码隐藏文件以处理加载和保存笔记。
将以下变量声明添加到
NotePage类:public sealed partial class NotePage : Page { private StorageFolder storageFolder = ApplicationData.Current.LocalFolder; private StorageFile? noteFile = null; private string fileName = "note.txt";保存笔记后,它将作为文本文件保存到应用的本地存储。
使用 StorageFolder 类访问应用的本地数据文件夹。 此文件夹特定于你的应用,因此无法由其他应用访问此处保存的笔记。 使用 StorageFile 类访问此文件夹中保存的文本文件。 文件的名称由
fileName变量表示。 目前,设置为fileName“note.txt”。为笔记页的 “已加载 ”事件创建事件处理程序。
public NotePage() { this.InitializeComponent(); // ↓ Add this. ↓ Loaded += NotePage_Loaded; } // ↓ Add this event handler method. ↓ private async void NotePage_Loaded(object sender, RoutedEventArgs e) { noteFile = (StorageFile)await storageFolder.TryGetItemAsync(fileName); if (noteFile is not null) { NoteEditor.Text = await FileIO.ReadTextAsync(noteFile); } }在此方法中,调用 TryGetItemAsync 从文件夹中检索文本文件。 如果文件不存在,则返回
null。 如果文件存在,请调用 ReadTextAsync ,将文件中的文本读取到NoteEditor控件的 Text 属性中。 (请记住,NoteEditor是在TextBoxXAML 文件中创建的控件。使用x:Name分配给代码隐藏文件中的代码隐藏文件中引用它。重要
需要使用关键字标记此方法
async,因为文件访问调用是异步的。 简言之,如果调用以 (like...Async) 结尾TryGetItemAsync的方法,则可以将 await 运算符添加到调用中。 这会让后续代码在等待的调用完成之前继续执行,并使 UI 保持响应。 使用await时,需要用 异步 关键字标记要从中调用的方法。 有关详细信息,请参阅 在 C# 中调用异步 API。
在文档中了解详细信息:
添加事件处理程序
接下来,为“保存”和“删除”按钮添加 Click 事件处理程序。 添加事件处理程序是在创建应用时经常执行的作,因此 Visual Studio 提供了多个功能来简化作。
在NotePage.xaml文件中,将光标置于
Content控件中的Button属性之后。 键入Click=。 此时,Visual Studio 应弹出如下所示的自动完成 UI:
- 按向下键选择“新建事件处理程序<”>,然后按 Tab。Visual Studio 将使用 完成属性
Click="Button_Click",并添加一个在代码隐藏文件中命名Button_Click的NotePage.xaml.cs事件处理程序方法。
现在,应将
Button_Click方法重命名为更有意义的内容。 你将在以下步骤中执行此作。- 按向下键选择“新建事件处理程序<”>,然后按 Tab。Visual Studio 将使用 完成属性
在 NotePage.xaml.cs中,找到已为你添加的方法:
private void Button_Click(object sender, RoutedEventArgs e) { }小窍门
若要在应用中查找代码,请单击 Visual Studio 标题栏中的 “搜索 ”并使用 “代码搜索 ”选项。 双击搜索结果以在代码编辑器中打开代码。
将光标置于“B”
Button之前,然后键入Save。 等待片刻,方法名称将以绿色突出显示。将鼠标悬停在方法名称上时,Visual Studio 将显示带有螺丝刀或灯泡图标的工具提示。 单击图标旁边的向下箭头按钮,然后单击“ Button_Click”重命名为“SaveButton_Click”。
Visual Studio 将在应用中的任意位置重命名该方法,包括在首次添加到
Button该应用的 XAML 文件中。对 “删除 ”按钮重复这些步骤,并将方法重命名为
DeleteButton_Click。
现在,事件处理程序已挂钩,可以添加代码以保存和删除笔记文件。
在
SaveButton_Click方法中添加此代码以保存文件。 请注意,还需要使用async关键字更新方法签名。private async void SaveButton_Click(object sender, RoutedEventArgs e) { if (noteFile is null) { noteFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting); } await FileIO.WriteTextAsync(noteFile, NoteEditor.Text); }在方法中
SaveButton_Click,首先检查是否已noteFile创建。null如果是,则必须在本地存储文件夹中创建一个新文件,其名称由fileName变量表示,并将该文件noteFile分配给变量。 然后,将控件中的TextBox文本写入由该文件表示的文件noteFile。在
DeleteButton_Click方法中添加此代码以删除文件。 还需要在此处使用async关键字更新方法签名。private async void DeleteButton_Click(object sender, RoutedEventArgs e) { if (noteFile is not null) { await noteFile.DeleteAsync(); noteFile = null; NoteEditor.Text = string.Empty; } }在方法中
DeleteButton_Click,首先检查是否存在noteFile。 如果确实这样做,请从本地存储文件夹中删除所noteFile表示的文件,并将其设置为noteFilenull。 然后,将控件中的TextBox文本重置为空字符串。重要
从文件系统中删除文本文件后,必须设置为
noteFilenull。 请记住,noteFile这是一个 StorageFile ,它提供对应用中系统文件的访问权限。 删除系统文件后,noteFile仍指向系统文件所在的位置,但不知道它不再存在。 如果现在尝试读取、写入或删除系统文件,将收到错误。通过按 Ctrl + S、单击工具栏中的“保存”图标或选择菜单“”来保存>NotePage.xaml.cs。
代码隐藏文件的最终代码应如下所示:
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using Windows.Storage;
namespace WinUINotes
{
public sealed partial class NotePage : Page
{
private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
private StorageFile? noteFile = null;
private string fileName = "note.txt";
public NotePage()
{
this.InitializeComponent();
Loaded += NotePage_Loaded;
}
private async void NotePage_Loaded(object sender, RoutedEventArgs e)
{
noteFile = (StorageFile)await storageFolder.TryGetItemAsync(fileName);
if (noteFile is not null)
{
NoteEditor.Text = await FileIO.ReadTextAsync(noteFile);
}
}
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
if (noteFile is null)
{
noteFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
}
await FileIO.WriteTextAsync(noteFile, NoteEditor.Text);
}
private async void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (noteFile is not null)
{
await noteFile.DeleteAsync();
noteFile = null;
NoteEditor.Text = string.Empty;
}
}
}
}
测试笔记
有了此代码,可以测试应用,以确保笔记保存并正确加载。
- 通过按 F5、单击工具栏中的“调试”按钮或选择菜单“开始>”来生成并运行项目。
- 键入文本输入框,然后按 “保存 ”按钮。
- 关闭应用,然后重启它。 输入的笔记应从设备的存储中加载。
- 按 “删除 ”按钮。
- 关闭应用,重启它。 应会显示一个新的空白笔记。
重要
确认保存和删除笔记正常工作后,请再次创建并保存新笔记。 在后续步骤中,你需要有一个保存的便笺来测试应用。