为笔记创建页面

现在,你将创建一个页面,允许用户编辑笔记,然后编写代码以保存或删除笔记。

小窍门

可以从 GitHub 存储库下载或查看本教程的代码。 若要查看此步骤中的代码,请参阅此提交: 备注页 - 初始

首先,将新页面添加至项目:

  1. 在 Visual Studio 的解决方案资源管理器 窗格中,右键单击 WinUINotes 项目 >“添加新>项...”

  2. 在“ 添加新项 ”对话框中,选择窗口左侧模板列表中的 WinUI 。 接下来,选择 空白页(WinUI 3) 模板。 将文件 NotePage.xaml命名,然后选择“ 添加”。

  3. 该文件 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>
    
  4. 通过按 Ctrl + S、单击工具栏中的“保存”图标或选择菜单“”来保存>NotePage.xaml。

    如果立即运行应用,则不会看到刚刚创建的备注页。 这是因为你仍然需要将其设置为控件的内容FrameMainWindow

  5. 打开MainWindow.xaml并设置为NotePageFrame,如下所示:

    <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 控件的关键部分细分一下:

新笔记页 UI,其中突出显示了 Visual Studio 的网格。

  • Grid.RowDefinitionsGrid.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 代码隐藏文件以处理加载和保存笔记。

  1. 将以下变量声明添加到 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 变量表示。 目前,设置为 fileNamenote.txt”。

  2. 为笔记页的 “已加载 ”事件创建事件处理程序。

    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 是在 TextBox XAML 文件中创建的控件。使用 x:Name 分配给代码隐藏文件中的代码隐藏文件中引用它。

    重要

    需要使用关键字标记此方法 async ,因为文件访问调用是异步的。 简言之,如果调用以 (like...Async) 结尾TryGetItemAsync的方法,则可以将 await 运算符添加到调用中。 这会让后续代码在等待的调用完成之前继续执行,并使 UI 保持响应。 使用 await时,需要用 异步 关键字标记要从中调用的方法。 有关详细信息,请参阅 在 C# 中调用异步 API

在文档中了解详细信息:

添加事件处理程序

接下来,为“保存”和“删除”按钮添加 Click 事件处理程序。 添加事件处理程序是在创建应用时经常执行的作,因此 Visual Studio 提供了多个功能来简化作。

  1. NotePage.xaml文件中,将光标置于Content控件中的Button属性之后。 键入 Click=。 此时,Visual Studio 应弹出如下所示的自动完成 UI:

    XAML 编辑器中 Visual Studio 新事件处理程序自动完成 UI 的屏幕截图

    • 按向下键选择“新建事件处理程序<”>,然后按 Tab。Visual Studio 将使用 完成属性Click="Button_Click",并添加一个在代码隐藏文件中命名Button_ClickNotePage.xaml.cs事件处理程序方法。

    现在,应将 Button_Click 方法重命名为更有意义的内容。 你将在以下步骤中执行此作。

  2. NotePage.xaml.cs中,找到已为你添加的方法:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
    
    }
    

    小窍门

    若要在应用中查找代码,请单击 Visual Studio 标题栏中的 “搜索 ”并使用 “代码搜索 ”选项。 双击搜索结果以在代码编辑器中打开代码。

    Visual Studio 中的搜索功能

  3. 将光标置于“B” Button 之前,然后键入 Save。 等待片刻,方法名称将以绿色突出显示。

  4. 将鼠标悬停在方法名称上时,Visual Studio 将显示带有螺丝刀或灯泡图标的工具提示。 单击图标旁边的向下箭头按钮,然后单击“ Button_Click”重命名为“SaveButton_Click”。

    Visual Studio 方法重命名弹出窗口 UI。

    Visual Studio 将在应用中的任意位置重命名该方法,包括在首次添加到 Button该应用的 XAML 文件中。

  5. “删除 ”按钮重复这些步骤,并将方法重命名为 DeleteButton_Click

现在,事件处理程序已挂钩,可以添加代码以保存和删除笔记文件。

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

  2. 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 仍指向系统文件所在的位置,但不知道它不再存在。 如果现在尝试读取、写入或删除系统文件,将收到错误。

  3. 通过按 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;
            }
        }
    }
}

测试笔记

有了此代码,可以测试应用,以确保笔记保存并正确加载。

  1. 通过按 F5、单击工具栏中的“调试”按钮或选择菜单“开始>”来生成并运行项目。
  2. 键入文本输入框,然后按 “保存 ”按钮。
  3. 关闭应用,然后重启它。 输入的笔记应从设备的存储中加载。
  4. “删除 ”按钮。
  5. 关闭应用,重启它。 应会显示一个新的空白笔记。

重要

确认保存和删除笔记正常工作后,请再次创建并保存新笔记。 在后续步骤中,你需要有一个保存的便笺来测试应用。