导航缓存和更改通知

第一步是执行所需的更改的基本设置:

  • 启用导航缓存。
  • Note.Text 属性实现属性更改通知。

完成此操作后,你将调整应用的其他部分以处理这些更改。

Tip

可以从 WinUI Notes 第 2 部分的 GitHub 存储库下载或查看本教程的完整代码。 若要查看项目的起点和终点之间的差异,请参阅此提交: 第 2 部分的更新

启用 NavigationCacheMode

默认情况下,每次导航时,都会使用其默认值创建新的 Page 实例。 在 WinUI Notes 应用中,这也是创建 notesModel 的地方,它用于存储所有 Note 实例。

AllNotesPage.xaml中,将 NavigationCacheMode 设置为 EnabledNavigationCacheMode="Enabled")。 启用 NavigationCacheMode 后,将保留相同的页面实例,因此每次导航时都不会创建新的 Page 实例,并且不会重新创建 notesModel

<Page
    x:Class="WinUI_Notes.Views.AllNotesPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI_Notes.Views"
    xmlns:models="using:WinUI_Notes.Models"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    //  ↓ Add this. ↓
    NavigationCacheMode="Enabled">

立即运行应用,你将注意到此更改的一些副作用。

  1. 编辑现有笔记时,返回后,所做的更改不会显示在“所有笔记”页面中。
  2. 创建并保存新笔记时,导航回时不会显示在所有备注列表中。
  3. 删除已有的笔记后,返回时,该笔记不会从所有笔记列表中移除。

你接下来将修复这些问题。

在文档中了解详细信息:

实现 INotifyPropertyChanged

编辑并保存现有笔记时,更改将保存到文件系统,但更改不会传播到所有备注列表。 这是因为 Note 类不会通知将 TextBox 连接到 Note 文本的数据绑定已发生更新。 若要使此通知发生,Note类需要为其INotifyPropertyChanged属性实现Text接口。

Note

WinUI 包含 Microsoft.UI.Xaml.Data.INotifyPropertyChanged 接口。 这仅由不使用.NET的 C++ 应用使用。

使用 .NET创建的 C# 应用改用 System.ComponentModel.INotifyPropertyChanged 接口。

INotifyPropertyChanged 的实现遵循一种固定模式。

  1. 为所需的命名空间添加 using 语句。

    // ↓ Add this. ↓
    using System.ComponentModel
    using System.Runtime.CompilerServices
    
  2. 实现 INotifyPropertyChanged。 该 Note 类现在实现此接口。

    // ↓ Update this. ↓
    public class Note : INotifyPropertyChanged
    
  3. _text属性创建后盾字段 (Text)。

    // ↓ Delete this. ↓
    // public string Text { get; set; } = string.Empty;
    
    // ↓ Add this. ↓
    private string _text = string.Empty;
    
  4. Text 属性修改为使用带有属性更改通知的 getter/setter 模式。

    // ↓ Add this. ↓
    public string Text
    {
        get => _text;
        set
        {
            if (_text != value)
            {
                _text = value;
                OnPropertyChanged();
            }
        }
    }
    
  5. 添加 INotifyPropertyChanged 接口所需的 PropertyChanged 事件。

    // ↓ Add this. ↓
    public event PropertyChangedEventHandler? PropertyChanged;
    
  6. 添加 OnPropertyChanged 方法。 此帮助程序方法使用 PropertyChanged 属性引发事件,用于自动属性名称检测。

    // ↓ Add this. ↓
    protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

Tip

可以使用GitHub Copilot在应用中快速实现INotifyPropertyChanged。 这些代码更改是使用提示生成的:“为 Note.Text 属性实现 INotifyPropertyChanged”。

绑定模式

现在,每当其值更改时,该 Text 属性都会通知绑定到它的任何 UI 元素,以便可以自动更新 UI。 但是,为了使绑定的 UI 元素对更新通知做出响应,必须确保使用了正确的 BindingMode

Important

选择正确的 BindingMode 非常重要;否则,数据绑定可能无法按预期工作。 (使用 {x:Bind} 时的一个常见错误是,在需要 OneWayTwoWay 时忘记更改默认 BindingMode。)

Name Description
OneTime 仅在创建绑定时更新目标属性。 默认值为 {x:Bind}.
OneWay 在创建绑定时更新目标属性。 对源对象的更改也可以传播到目标。
TwoWay 在任一更改时更新目标对象或源对象。 创建绑定后,将从源更新目标属性。

AllNotesPage.xaml 中,找到 Page.Resources 中的 NoteItemTemplate。 然后,在模板中找到与 Text 属性绑定的 TextBlock。 更新绑定以使用 OneWay 绑定模式。

// ↓ Update this. ↓              ↓    ↓
<TextBlock Text="{x:Bind Text, Mode=OneWay}"
           Margin="4" TextWrapping="Wrap"
           TextTrimming="WordEllipsis"/>

由于用户无法更新 TextBlock 中的文本,因此只需要一个 OneWay 绑定,从源(Note.Text)到目标(TextBlock.Text)。

在文档中了解详细信息: