Cache de navegação e notificação de alterações

O primeiro passo é fazer a configuração básica para as alterações que precisa de fazer:

  • Ative a cache de navegação.
  • Implemente notificações de alteração de propriedade para a Note.Text propriedade.

Uma vez concluído, vais adaptar outras partes da aplicação para lidar com estas mudanças.

Sugestão

Pode descarregar ou ver o código completo deste tutorial no repositório do GitHub em WinUI Notes parte 2. Para ver as diferenças entre os pontos inicial e final do projeto, consulte este commit: atualizações para a parte 2.

Ativar NavigationCacheMode

Por defeito, é criada uma nova instância de Página com os seus valores predefinidos sempre que ocorre navegação. Na aplicação WinUI Notes, é também aqui que o notesModel, que armazena todas as Note instâncias, é criado.

Em AllNotesPage.xaml, defina o NavigationCacheMode para Ativado (NavigationCacheMode="Enabled"). Com NavigationCacheMode ativado, mantém-se a mesma instância da página, pelo que não é criada uma nova instância de Page em cada navegação e notesModel não é recriado.

<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">

Executa a aplicação agora e vais notar alguns efeitos secundários desta mudança.

  1. Quando editas uma nota existente, as tuas alterações não são refletidas na página de todas as notas quando voltas a navegar.
  2. Quando crias e guardas uma nova nota, ela não aparece na lista de todas as notas quando voltas atrás.
  3. Quando apagas uma nota existente, ela não é removida da lista de todas as notas quando voltas atrás.

Vais resolver estes problemas a seguir.

Saiba mais nos documentos:

Implementar INotifyPropertyChanged

Quando editas e guardas uma nota existente, a tua alteração é guardada no sistema de ficheiros, mas a alteração não é propagada para a lista de todas as notas. Isto acontece porque a classe Note não notifica a associação de dados, que liga o texto de Note a TextBox, de que ocorreu uma atualização. Para que esta notificação aconteça, a Note classe precisa de implementar a INotifyPropertyChanged interface para a sua Text propriedade.

Note

O WinUI inclui a interface Microsoft.UI.Xaml.Data.INotifyPropertyChanged. Isto é usado apenas por aplicações C++, que não usam .NET.

As aplicações C# criadas com .NET utilizam a interface System.ComponentModel.INotifyPropertyChanged em vez disso.

A implementação de INotifyPropertyChanged segue um padrão definido.

  1. Adicionar using declarações para os espaços de nomes necessários.

    // ↓ Add this. ↓
    using System.ComponentModel
    using System.Runtime.CompilerServices
    
  2. Implementar INotifyPropertyChanged. A Note classe implementa agora esta interface.

    // ↓ Update this. ↓
    public class Note : INotifyPropertyChanged
    
  3. Crie um campo de apoio (_text) para a Text propriedade.

    // ↓ Delete this. ↓
    // public string Text { get; set; } = string.Empty;
    
    // ↓ Add this. ↓
    private string _text = string.Empty;
    
  4. Modificar a propriedade Text para usar o padrão getter/setter com notificação de alteração da propriedade.

    // ↓ Add this. ↓
    public string Text
    {
        get => _text;
        set
        {
            if (_text != value)
            {
                _text = value;
                OnPropertyChanged();
            }
        }
    }
    
  5. Adicione o evento PropertyChanged exigido pela INotifyPropertyChanged interface.

    // ↓ Add this. ↓
    public event PropertyChangedEventHandler? PropertyChanged;
    
  6. Adicione o método OnPropertyChanged. Este método auxiliar dispara o evento PropertyChanged através do atributo CallerMemberName para deteção automática do nome da propriedade.

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

Sugestão

Podes usar o GitHub Copilot para implementar INotifyPropertyChanged rapidamente na tua aplicação. Estas alterações ao código foram geradas com o prompt: "Implementar INotifyPropertyChanged para a propriedade Note.Text".

Modo de ligação

Agora a Text propriedade notifica quaisquer elementos da interface associada sempre que o seu valor mude, por isso a sua interface pode ser atualizada automaticamente. No entanto, para que os elementos da interface vinculados reajam à notificação de atualização, tens de garantir que o BindingMode correto é usado.

Importante

É importante escolher o BindingMode correto; caso contrário, a vinculação de dados pode não funcionar conforme o esperado. (O erro comum com {x:Bind} é esquecer-se de alterar o valor padrão BindingMode quando OneWay ou TwoWay for necessário.)

Name Description
OneTime Atualiza a propriedade de destino somente quando a associação é criada. Padrão para {x:Bind}.
OneWay Atualiza a propriedade de destino quando a associação é criada. As alterações no objeto de origem também podem se propagar para o destino.
TwoWay Atualiza o destino ou o objeto de origem quando ambos são alterados. Quando a associação é criada, a propriedade de destino é atualizada a partir da origem.

Em AllNotesPage.xaml, encontre o NoteItemTemplate em Page.Resources. Depois, no modelo, encontre o TextBlock que está associado à propriedade Text. Atualize a ligação para usar o modo de ligação OneWay.

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

Como o utilizador não pode atualizar o texto no TextBlock, apenas é necessária uma OneWay ligação, da fonte (Note.Text) para o destino (TextBlock.Text).

Saiba mais nos documentos: