Кэш навигации и уведомление об изменениях

Первым шагом является выполнение базовой настройки изменений, которые необходимо внести:

  • включите кэш навигации.
  • реализуйте уведомления об изменении свойства для свойства Note.Text.

Как только это будет сделано, вы адаптируете остальные части приложения к этим изменениям.

Tip

Вы можете скачать или просмотреть полный код для этого руководства из репозитория GitHub в WinUI Notes часть 2. Чтобы увидеть различия между начальным и конечным состоянием проекта, см. этот коммит: обновления для части 2.

Включить NavigationCacheMode

По умолчанию создается новый экземпляр страницы со значениями по умолчанию при каждом переходе. В приложении WinUI Notes здесь также создаётся notesModel, который хранит все экземпляры Note.

В AllNotesPage.xaml задайте для NavigationCacheMode значение Enabled (NavigationCacheMode="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.

Замечание

WinUI включает интерфейс Microsoft.UI.Xaml.Data.INotifyPropertyChanged. Это используется только приложениями C++, которые не используют .NET.

Приложения C#, созданные с помощью .NET, используют вместо этого интерфейс 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. Добавьте событие PropertyChanged , необходимое интерфейсом INotifyPropertyChanged .

    // ↓ Add this. ↓
    public event PropertyChangedEventHandler? PropertyChanged;
    
  6. OnPropertyChanged Добавьте метод. Этот вспомогательный PropertyChanged метод вызывает событие с помощью атрибута CallerMemberName для автоматического обнаружения имени свойства.

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

Tip

Вы можете использовать GitHub Copilot для быстрой реализации INotifyPropertyChanged в приложении. Эти изменения кода были сгенерированы по запросу: "Реализовать INotifyPropertyChanged для свойства Note.Text".

Режим привязки

Text Теперь свойство уведомляет все элементы пользовательского интерфейса, привязанные к нему при изменении его значения, чтобы пользовательский интерфейс можно было обновлять автоматически. Тем не менее, чтобы связанные элементы пользовательского интерфейса реагировали на уведомление об обновлении, необходимо убедиться, что используется правильный BindingMode .

Important

Важно выбрать правильный BindingMode; В противном случае привязка данных может не работать должным образом. (Распространенная ошибка заключается в {x:Bind} том, чтобы забыть изменить значение по умолчанию BindingMode при OneWayTwoWay необходимости.)

Name Description
OneTime Обновляет целевое свойство только при создании привязки. Значение по умолчанию для {x:Bind}.
OneWay Обновляет целевое свойство при создании привязки. Изменения исходного объекта также могут распространяться на целевой объект.
TwoWay Обновляет целевой объект или исходный объект при изменении. При создании привязки целевое свойство обновляется из источника.

В AllNotesPage.xaml, найдите NoteItemTemplate в Page.Resources. Затем в шаблоне найдите TextBlock, который привязан к свойству Text. Обновите привязку, чтобы использовать режим привязки OneWay .

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

Поскольку пользователь не может изменять текст в TextBlock, нужна только привязка OneWay от источника (Note.Text) к цели (TextBlock.Text).

Дополнительные сведения см. в документации: