Partilhar via


Adicionar uma vista e um modelo para a nota

Esta parte do tutorial apresenta os conceitos de modos de exibição e modelos de dados.

Nas etapas anteriores do tutorial, você adicionou uma nova página ao projeto que permite ao usuário salvar, editar ou excluir uma única nota. No entanto, como o aplicativo precisa lidar com mais de uma nota, você precisa adicionar outra página que exiba todas as anotações (chame-a).AllNotesPage Esta página permite que o usuário escolha uma nota para abrir na página do editor para que possa visualizá-la, editá-la ou excluí-la. Ele também deve permitir que o usuário crie uma nova nota.

Para conseguir isso, AllNotesPage precisa ter uma coleção de notas, e uma maneira de exibir a coleção. É aqui que o aplicativo tem problemas porque os dados da nota estão fortemente vinculados ao NotePage arquivo. No AllNotesPage, você deseja apenas exibir todas as anotações em uma lista ou outra exibição de coleção, com informações sobre cada nota, como a data em que foi criada e uma visualização do texto. Com o texto da nota firmemente vinculado ao TextBox controle, não há como fazer isso.

Antes de adicionar uma página para mostrar todas as notas, vamos fazer algumas alterações para separar os dados da nota da apresentação da nota.

Vistas e modelos

Normalmente, um aplicativo WinUI tem pelo menos uma camada de exibição e uma camada de dados.

A camada de exibição define a interface do usuário usando marcação XAML. A marcação inclui expressões de vinculação de dados (como x:Bind) que definem a conexão entre componentes específicos da interface do usuário e membros de dados. Os arquivos code-behind às vezes são usados como parte da camada de exibição para conter código adicional necessário para personalizar ou manipular a interface do usuário ou para extrair dados de argumentos do manipulador de eventos antes de chamar um método que executa o trabalho nos dados.

A camada de dados, ou modelo, define os tipos que representam os dados do seu aplicativo e a lógica relacionada. Essa camada é independente da camada de exibição e você pode criar várias exibições diferentes que interagem com os dados.

Atualmente, o NotePage representa uma exibição de dados (o texto da nota). No entanto, depois que os dados são lidos no aplicativo a partir do arquivo do sistema, eles existem apenas na Text propriedade do TextBox in NotePage. Não é representado na aplicação de uma forma que lhe permita apresentar os dados de formas diferentes ou em locais diferentes; ou seja, o aplicativo não tem uma camada de dados. Você reestruturará o projeto agora para criar a camada de dados.

Separe a vista e o modelo

Sugestão

Você pode baixar ou visualizar o código para este tutorial no repositório GitHub. Para ver o código como está nesta etapa, consulte este commit: note page - view-model.

Refatore o código existente para separar o modelo da exibição. As próximas etapas organizarão o código para que as exibições e os modelos sejam definidos separadamente uns dos outros.

  1. No Gerenciador de Soluções, clique com o botão direito do WinUINotes mouse no projeto e selecione Adicionar>Nova Pasta. Dê um nome à pasta Models.

  2. Clique com o botão direito do WinUINotes mouse no projeto novamente e selecione Adicionar>nova pasta. Dê um nome à pasta Views.

  3. Localize o NotePage.xaml item e arraste-o para a Views pasta. O NotePage.xaml.cs arquivo deve ser movido com ele.

    Observação

    Quando você move um arquivo, o Visual Studio geralmente solicita um aviso sobre como a operação de movimentação pode levar muito tempo. Isso não deve ser um problema aqui, pressione OK se vir este aviso.

    Visual Studio também pode perguntar se você deseja ajustar o namespace do arquivo movido. Selecione Não. Você alterará o namespace nas próximas etapas.

Atualizar o namespace de exibição

Agora que a exibição foi movida para a Views pasta, você precisará atualizar os namespaces para corresponder. O namespace para os arquivos XAML e code-behind das páginas é definido como WinUINotes. Isso precisa ser atualizado para WinUINotes.Views.

  1. No painel Gerenciador de Soluções , expanda NotePage.xaml para revelar o arquivo code-behind.

  2. Clique duas vezes no NotePage.xaml.cs item para abrir o editor de código, se ele ainda não estiver aberto. Altere o namespace para WinUINotes.Views:

    namespace WinUINotes.Views
    
  3. Clique duas vezes no NotePage.xaml item para abrir o editor XAML se ele ainda não estiver aberto. O namespace antigo é referenciado por meio do atributo x:Class, que define qual tipo de classe é o code-behind para o XAML. Esta entrada não é apenas o namespace, mas o namespace com o tipo. Altere o valor x:Class para WinUINotes.Views.NotePage:

    x:Class="WinUINotes.Views.NotePage"
    

Corrigir a referência de namespace em MainWindow

Na etapa anterior, você criou a página de anotações e atualizou MainWindow.xaml para navegar até ela. Lembre-se de que ele foi mapeado com o mapeamento de local: namespace. É prática comum mapear o nome local para o namespace raiz do seu projeto, e o modelo de projeto do Visual Studio já faz isso para você (xmlns:local="using:WinUINotes"). Agora que a página foi movida para um novo namespace, o mapeamento de tipo no XAML agora é inválido.

Felizmente, você pode adicionar seus próprios mapeamentos de namespace conforme necessário. Você precisa fazer isso para acessar itens em diferentes pastas que você cria em seu projeto. Esse novo namespace XAML será mapeado para o namespace de WinUINotes.Views, então nomeie-o views. A declaração deve ser semelhante ao seguinte atributo: xmlns:views="using:WinUINotes.Views".

  1. No painel Gerenciador de Soluções , clique duas vezes na entrada MainWindow.xaml para abri-la no editor XAML.

  2. Adicione este novo mapeamento de namespace na linha abaixo do mapeamento para local:

    xmlns:views="using:WinUINotes.Views"
    
  3. O local namespace XAML foi usado para definir a Frame.SourcePageType propriedade, portanto, altere-a para views lá. Seu XAML agora deve ter esta aparência:

    <Window
        x:Class="WinUINotes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WinUINotes"
        xmlns:views="using:WinUINotes.Views"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="WinUI Notes">
    
        <!-- ... Unchanged XAML not shown. -->
    
            <Frame x:Name="rootFrame" Grid.Row="1"
                   SourcePageType="views:NotePage"/>
    
        <!-- ... Unchanged XAML not shown. -->
    
    </Window>
    
  4. Compile e execute a aplicação. O aplicativo deve ser executado sem erros de compilador e tudo ainda deve funcionar como antes.

Definir o modelo

Atualmente, o modelo (os dados) está incorporado na vista de notas. Você criará uma nova classe para representar os dados de uma página de anotação:

  1. No painel Gerenciador de Soluções , clique com o botão direito do mouse na pasta e selecione Adicionar Classe....

  2. Nomeie a classe Note.cs e pressione Add. O Note.cs arquivo será aberto no editor de códigos.

  3. Substitua o Note.cs código no arquivo por este código, que faz a classe public e adiciona propriedades e métodos para manipular uma nota:

    using System;
    using System.Threading.Tasks;
    using Windows.Storage;
    
    namespace WinUINotes.Models
    {
        public class Note
        {
            private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
            public string Filename { get; set; } = string.Empty;
            public string Text { get; set; } = string.Empty;
            public DateTime Date { get; set; } = DateTime.Now;
    
            public Note()
            {
                Filename = "notes" + DateTime.Now.ToBinary().ToString() + ".txt";
            }
    
            public async Task SaveAsync()
            {
                // Save the note to a file.
                StorageFile noteFile = (StorageFile)await storageFolder.TryGetItemAsync(Filename);
                if (noteFile is null)
                {
                    noteFile = await storageFolder.CreateFileAsync(Filename, CreationCollisionOption.ReplaceExisting);
                }
                await FileIO.WriteTextAsync(noteFile, Text);
            }
    
            public async Task DeleteAsync()
            {
                // Delete the note from the file system.
                StorageFile noteFile = (StorageFile)await storageFolder.TryGetItemAsync(Filename);
                if (noteFile is not null)
                {
                    await noteFile.DeleteAsync();
                }
            }
        }
    }
    
  4. Salve o arquivo.

Você notará que esse código é muito semelhante ao código do , NotePage.xaml.cscom algumas alterações e adições.

Filename e Text foram alterados para public propriedades, e uma nova Date propriedade foi adicionada.

O código para salvar e excluir os arquivos foi colocado em public métodos. É basicamente idêntico ao código que você usou nos manipuladores de eventos de botão Click no NotePage, mas o código extra para atualizar a exibição depois que o arquivo é excluído foi removido. Não é necessário aqui porque você usará a vinculação de dados para manter o modelo e a exibição sincronizados.

Essas assinaturas de método assíncrono retornam Task em vez de void. A Task classe representa uma única operação assíncrona que não retorna um valor. A menos que a assinatura do método exija void, como é o caso dos manipuladores de eventos, Click os async métodos devem retornar um Taskarquivo .

Você também não manterá mais uma referência ao StorageFile que contém a nota. Você apenas tenta obter o arquivo quando precisar dele para salvar ou excluir.

No NotePage, você usou um espaço reservado para o nome do arquivo: note.txt. Agora que o aplicativo suporta mais de uma nota, os nomes de arquivo para notas salvas precisam ser diferentes e exclusivos. Para fazer isso, defina a Filename propriedade no construtor. Você pode usar o método DateTime.ToBinary para criar uma parte do nome do arquivo com base na hora atual e tornar os nomes de arquivo exclusivos. O nome do ficheiro gerado tem o seguinte aspeto: notes-8584626598945870392.txt.

Atualizar a página de notas

Agora você pode atualizar a NotePage exibição para usar o modelo de dados e excluir o Note código que foi movido para o Note modelo.

  1. Abra o arquivo Views\NotePage.xaml.cs se ele ainda não estiver aberto no editor.

  2. Após a última using instrução na parte superior da página, adicione uma nova using instrução para dar ao seu código acesso às classes na pasta e namespace Models .

    using WinUINotes.Models;
    
  3. Exclua estas linhas da classe:

    private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    private StorageFile? noteFile = null;
    private string fileName = "note.txt";
    
  4. Em vez disso, adicione um Note objeto nomeado noteModel em seu lugar. Isso representa os dados da nota que NotePage fornecem uma exibição de.

    private Note? noteModel;
    
  5. Você também não precisa mais do NotePage_Loaded manipulador de eventos. Você não estará lendo texto diretamente do arquivo de texto para o TextBox. Em vez disso, o texto da nota será lido em Note objetos. Você adicionará o código para isso quando adicionar o AllNotesPage em uma etapa posterior. Exclua essas linhas.

    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);
        }
    }
    
  6. Substitua o código no SaveButton_Click método por este:

    if (noteModel is not null)
    {
        await noteModel.SaveAsync();
    }
    
  7. Substitua o código no DeleteButton_Click método por este:

    if (noteModel is not null)
    {
        await noteModel.DeleteAsync();
    }
    

Agora você pode atualizar o arquivo XAML para usar o Note modelo. Anteriormente, você lia o texto diretamente do arquivo de texto para a TextBox.Text propriedade no arquivo code-behind. Agora, você usa a vinculação de dados para a Text propriedade.

  1. Abra o arquivo Views\NotePage.xaml se ele ainda não estiver aberto no editor.

  2. Adicione um Text atributo ao TextBox controle. Vincule-o à Text propriedade de noteModel: Text="{x:Bind noteModel.Text, Mode=TwoWay}".

  3. Atualize o Header para vincular à Date propriedade de noteModel: Header="{x:Bind noteModel.Date.ToString()}".

    <TextBox x:Name="NoteEditor"
             <!-- ↓ Add this line. ↓ -->
             Text="{x:Bind noteModel.Text, Mode=TwoWay}"
             AcceptsReturn="True"
             TextWrapping="Wrap"
             PlaceholderText="Enter your note"
             <!-- ↓ Update this line. ↓ -->
             Header="{x:Bind noteModel.Date.ToString()}"
             ScrollViewer.VerticalScrollBarVisibility="Auto"
             Width="400"
             Grid.Column="1"/>
    

A associação de dados é uma maneira de a interface do usuário do seu aplicativo exibir dados e, opcionalmente, permanecer sincronizada com esses dados. A Mode=TwoWay configuração na associação significa que as TextBox.Text propriedades e noteModel.Text são sincronizadas automaticamente. Quando o texto é atualizado no TextBox, as alterações são refletidas na Text propriedade do , e se noteModel for alterado, as atualizações são refletidas noteModel.TextTextBoxno .

A Header propriedade usa o padrão Mode de OneTime porque a noteModel.Date propriedade não é alterada depois que o arquivo é criado. Esse código também demonstra um recurso poderoso de x:Bindligação de função chamada, que permite usar uma função como ToString uma etapa no caminho de ligação.

Importante

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

Nome 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. Padrão para {Binding}.
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.

A vinculação de dados oferece suporte à separação de seus dados e da interface do usuário, e isso resulta em um modelo conceitual mais simples, bem como melhor legibilidade, estabilidade e manutenção do seu aplicativo.

No WinUI, há dois tipos de vinculação que você pode escolher:

  • A {x:Bind} extensão de marcação é processada em tempo de compilação. Alguns de seus benefícios são o desempenho aprimorado e a validação em tempo de compilação de suas expressões de vinculação. É recomendado para vinculação em aplicativos WinUI.
  • A {Binding} extensão de marcação é processada em tempo de execução e usa inspeção de objeto de tempo de execução de uso geral.

Saiba mais nos documentos:

Vinculação de dados e MVVM

Model-View-ViewModel (MVVM) é um padrão de design de arquitetura de interface do usuário para dissociar código de interface do usuário e não-interface do usuário que é popular entre os desenvolvedores .NET. Você provavelmente verá e ouvirá isso mencionado à medida que aprender mais sobre como criar aplicativos WinUI. Separar as visualizações e os modelos, como você fez aqui, é o primeiro passo para uma implementação MVVM completa do aplicativo, mas é até onde você vai neste tutorial.

Observação

Usamos o termo "modelo" para nos referir ao modelo de dados neste tutorial, mas é importante observar que esse modelo está mais alinhado com o ViewModel em uma implementação MVVM completa, ao mesmo tempo em que incorpora aspetos do modelo.

Para saber mais sobre MVVM, consulte estes recursos: