Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este tutorial foi projetado para demonstrar como criar um aplicativo de interface do usuário do aplicativo .NET multiplataforma (.NET MAUI) que usa apenas código multiplataforma. Ou seja, o código que você escreve não será específico para Windows, Android, iOS ou macOS. O aplicativo que você criará será um aplicativo de anotação, no qual o usuário pode criar, salvar e carregar várias anotações.
Neste tutorial, você aprenderá como:
- Crie um aplicativo .NET MAUI Shell.
- Execute seu aplicativo na plataforma escolhida.
- Defina a interface do usuário com xAML (linguagem de marcação de aplicativo eXtensible) e interaja com elementos XAML por meio do código.
- Crie exibições e associe-as aos dados.
- Use a navegação para mover de e para páginas.
Você usará o Visual Studio 2022 para criar um aplicativo com o qual você pode inserir uma nota e salvá-la no armazenamento do dispositivo. O aplicativo final é mostrado aqui:
Criar um projeto
Antes de começar este tutorial, você deve seguir Criar seu primeiro artigo de aplicativo. Ao criar o projeto, use as seguintes configurações:
Nome do projeto
Isso deve ser definido como
Notes. Se o projeto tiver o nome de algo diferente, o código que você copiar e colar deste tutorial poderá resultar em erros de build.Coloque a solução e o projeto no mesmo diretório
Desmarque essa configuração.
Escolha a versão mais recente do .NET ao criar seu projeto.
Selecionar o dispositivo de destino
Os aplicativos .NET MAUI são projetados para serem executados em vários sistemas operacionais e dispositivos. Você precisará selecionar qual destino deseja testar e depurar seu aplicativo.
Defina o Destino de Depuração na barra de ferramentas do Visual Studio para o dispositivo com o qual você deseja depurar e testar. As etapas a seguir demonstram como definir o Destino de Depuração para Android:
- Selecione o botão suspenso Destino de Depuração.
- Selecione o item Android Emulators.
- Selecione o dispositivo emulador.
Personalizar o shell do aplicativo
Quando o Visual Studio cria um projeto MAUI do .NET, quatro arquivos de código importantes são gerados. Elas podem ser vistas no painel Gerenciador de Soluções do Visual Studio:
Esses arquivos ajudam a configurar e executar o aplicativo MAUI do .NET. Cada arquivo serve a uma finalidade diferente, descrita abaixo:
MauiProgram.cs
Este é um arquivo de código que inicializa seu aplicativo. O código nesse arquivo serve como o ponto de entrada entre plataformas do aplicativo, que configura e inicia o aplicativo. O código de inicialização do modelo aponta para a classe
Appdefinida pelo arquivo App.xaml.App.xaml e App.xaml.cs
Apenas para manter as coisas simples, ambos os arquivos são conhecidos como um único arquivo. Geralmente, há dois arquivos com qualquer arquivo XAML, o arquivo .xaml em si e um arquivo de código correspondente que é um item filho dele no Gerenciador de Soluções. O arquivo .xaml contém marcação XAML e o arquivo de código contém o código criado pelo usuário para interagir com a marcação XAML.
O arquivo App.xaml contém recursos XAML em todo o aplicativo, como cores, estilos ou modelos. O arquivo App.xaml.cs geralmente contém código que cria uma instância do aplicativo Shell. Neste projeto, ele aponta para a classe
AppShell.AppShell.xaml e AppShell.xaml.cs
Esse arquivo define a classe
AppShell, que é usada para definir a hierarquia visual do aplicativo.MainPage.xaml e MainPage.xaml.cs
Esta é a página de inicialização exibida pelo aplicativo. O arquivo MainPage.xaml define a interface do usuário (interface do usuário) da página. MainPage.xaml.cs contém o code-behind para o XAML, como código para um evento de clique de botão.
Adicionar uma página "sobre"
A primeira personalização que você fará é adicionar outra página ao projeto. Esta página é uma página "sobre", que representa informações sobre esse aplicativo, como o autor, a versão e talvez um link para obter mais informações.
No painel Gerenciador de Soluções do Visual Studio, clique com o botão direito do mouse no projeto >Adicionar>Novo Item.
Na caixa de diálogo Adicionar Novo Item , se você vir um conjunto limitado de modelos, clique em Mostrar todos os modelos para exibir todos os modelos disponíveis.
Na caixa de diálogo Adicionar Novo Item, selecione .NET MAUI na lista de modelos no lado esquerdo da janela. Em seguida, selecione o modelo do .NET MAUI ContentPage (XAML). Nomeie o arquivo AboutPage.xaml e selecione Adicionar.
O arquivo AboutPage.xaml abrirá uma nova guia de documento, exibindo toda a marcação XAML que representa a interface do usuário da página. Substitua a marcação XAML pela marcação a seguir:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Notes.AboutPage"> <VerticalStackLayout Spacing="10" Margin="10"> <HorizontalStackLayout Spacing="10"> <Image Source="dotnet_bot.png" SemanticProperties.Description="The dot net bot waving hello!" HeightRequest="64" /> <Label FontSize="22" FontAttributes="Bold" Text="Notes" VerticalOptions="End" /> <Label FontSize="22" Text="v1.0" VerticalOptions="End" /> </HorizontalStackLayout> <Label Text="This app is written in XAML and C# with .NET MAUI." /> <Button Text="Learn more..." Clicked="LearnMore_Clicked" /> </VerticalStackLayout> </ContentPage>Salve o arquivo pressionando Ctrl+S ou selecionando o menu Salvar Arquivo>AboutPage.xaml.
Vamos especificar as partes principais dos controles XAML colocados na página:
<ContentPage>é o objeto raiz da classeAboutPage.<VerticalStackLayout>é o único objeto filho do ContentPage. ContentPage só pode ter um objeto filho. O tipo VerticalStackLayout pode ter vários filhos. Este controle de layout organiza seus elementos filhos verticalmente, um após o outro.<HorizontalStackLayout>opera da mesma forma que um<VerticalStackLayout>, porém, seus filhos são organizados horizontalmente.<Image>exibe uma imagem, nesse caso, ela está usando a imagemdotnet_bot.pngque vem com todos os projetos do .NET MAUI.Important
O arquivo adicionado ao projeto é, na verdade,
dotnet_bot.svg. O .NET MAUI converte arquivos SVG (Gráficos vetoriais escalonáveis) em arquivos PNG (Portable Network Graphic) com base no dispositivo de destino. Portanto, ao adicionar um arquivo SVG ao seu projeto de aplicativo .NET MAUI, ele deve ser referenciado de XAML ou C# com uma extensão.png. A única referência ao arquivo SVG deve estar no arquivo de projeto.<Label>controla o texto de exibição.<Button>controles podem ser pressionados pelo usuário, o que gera o eventoClicked. Você pode executar o código em resposta ao eventoClicked.Clicked="LearnMore_Clicked"O evento
Clickeddo botão é atribuído ao manipulador de eventosLearnMore_Clicked, que será definido no arquivo code-behind. Você criará esse código na próxima etapa.
Manipular o evento Clicked
O próximo passo é adicionar o código do evento Clicked do botão.
No painel Solution Explorer do Visual Studio, expanda o arquivo AboutPage.xaml para revelar seu arquivo code-behind AboutPage.xaml.cs. Em seguida, clique duas vezes no arquivo AboutPage.xaml.cs para abri-lo no editor de código.
Adicione o seguinte código de manipulador de eventos
LearnMore_Clicked, que abre o navegador do sistema em um URL específico:private async void LearnMore_Clicked(object sender, EventArgs e) { // Navigate to the specified URL in the system browser. await Launcher.Default.OpenAsync("https://aka.ms/maui"); }Observe que a palavra-chave
asyncfoi adicionada à declaração do método, que permite o uso da palavra-chaveawaitao abrir o navegador do sistema.Salve o arquivo pressionando Ctrl+S ou selecionando o menu Salvar arquivo>AboutPage.xaml.cs.
Agora que o XAML e o code-behind do AboutPage estão concluídos, você precisará exibi-lo no aplicativo.
Adicionar recursos de imagem
Alguns controles podem usar imagens, o que aprimora a forma como os usuários interagem com seu aplicativo. Nesta seção, você baixará duas imagens que usará em seu aplicativo, juntamente com duas imagens alternativas para uso com o iOS.
Baixe as seguintes imagens:
- Ícone: Sobre. Essa imagem é usada como um ícone para a página sobre a qual você criou anteriormente.
- Ícone: Anotações. Essa imagem é usada como um ícone para a página de anotações que você criará na próxima parte deste tutorial.
- Ícone: Sobre (iOS)
- Ícone: Anotações (iOS)
Depois de baixar as imagens, você pode movê-las com o Explorador de Arquivos para a pasta Recursos\Imagens do projeto. Qualquer arquivo nessa pasta é incluído automaticamente no projeto como um recurso MauiImage. Você também pode usar o Visual Studio para adicionar as imagens ao seu projeto. Se você mover as imagens manualmente, ignore o procedimento a seguir.
Important
Não ignore o download das imagens específicas do iOS; eles são necessários para concluir este tutorial.
Mover as imagens com o Visual Studio
No painel Gerenciador de Soluções do Visual Studio, expanda a pasta Recursos, que revela a pasta Imagens.
Tip
Você pode usar o Explorador de Arquivos para arrastar e soltar as imagens diretamente no painel Gerenciador de Soluções, na parte superior da pasta Imagens. Isso move automaticamente os arquivos para a pasta e os inclui no projeto. Se você optar por arrastar e soltar os arquivos, ignore o restante deste procedimento.
Clique com o botão direito do mouse em imagens e selecione Adicionar>Item Existente.
Navegue até a pasta que contém as imagens baixadas.
Altere o filtro para filtro de tipo de arquivo em Arquivos de Imagem.
Mantenha pressionada a tecla Ctrl e clique em cada uma das imagens baixadas e pressione Adicionar
Modificar o shell do aplicativo
Conforme observado no início deste artigo, a classe define a AppShell hierarquia visual de um aplicativo, a marcação XAML usada na criação da interface do usuário do aplicativo. Atualize o XAML para adicionar um controle TabBar:
Clique duas vezes no arquivo AppShell.xaml no painel Gerenciador de Soluções para abrir o editor XAML. Substitua a marcação XAML pelo código a seguir:
<?xml version="1.0" encoding="UTF-8" ?> <Shell x:Class="Notes.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Notes"> <TabBar> <ShellContent Title="Notes" ContentTemplate="{DataTemplate local:MainPage}" Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" /> <ShellContent Title="About" ContentTemplate="{DataTemplate local:AboutPage}" Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" /> </TabBar> </Shell>Salve o arquivo pressionando Ctrl+S ou selecionando o menu Salvar Arquivo>AppShell.xaml.
Vamos dividir as partes principais do XAML:
-
<Shell>é o objeto raiz da marcação XAML. -
<TabBar>é o conteúdo do Shell. - Dois objetos
<ShellContent>dentro do<TabBar>. Antes de substituir o código do modelo, havia um único objeto<ShellContent>, apontando para a páginaMainPage.
O TabBar e seus filhos não representam elementos de interface do usuário, mas sim a organização da hierarquia visual do aplicativo. O Shell usa esses objetos e produz a interface do usuário para o conteúdo, com uma barra na parte superior representando cada página. A propriedade ShellContent.Icon para cada página usa a extensão de marcação OnPlatform. Essa extensão de marcação XAML é usada para especificar valores diferentes para plataformas diferentes. Neste exemplo, cada plataforma usa o ícone icon_about.png por padrão, mas o iOS e o MacCatalyst usam icon_about_ios.png.
Cada objeto <ShellContent> está apontando para uma página a ser exibida. Isso é definido pela propriedade ContentTemplate.
Executar o aplicativo
Execute o aplicativo pressionando F5 ou pressionando o botão reproduzir na parte superior do Visual Studio:
Você verá que há duas guias: Anotações e sobre. Pressione a guia Sobre e o aplicativo navega até o AboutPage que você criou. Pressione o botão Saiba mais para abrir o navegador da Web.
Feche o aplicativo e retorne ao Visual Studio. Se você estiver usando o emulador do Android, encerre o aplicativo no dispositivo virtual ou pressione o botão parar na parte superior do Visual Studio:
Criar uma página para uma anotação
Agora que o aplicativo contém o MainPage e AboutPage, você pode começar a criar o restante do aplicativo. Primeiro, você criará uma página que permite que um usuário crie e exiba a anotação e, em seguida, você escreverá o código para carregar e salvar a nota.
A página de anotação exibirá a nota e permitirá que você a salve ou exclua. Primeiro, adicione a nova página ao projeto:
No painel Gerenciador de Soluções do Visual Studio, clique com o botão direito do mouse no projeto >Adicionar>Novo Item.
Na caixa de diálogo Adicionar Novo Item , se você vir um conjunto limitado de modelos, clique em Mostrar todos os modelos para exibir todos os modelos disponíveis.
Selecione .NET MAUI na lista de modelos no lado esquerdo da janela. Em seguida, selecione o modelo do .NET MAUI ContentPage (XAML). Nomeie o arquivo NotePage.xaml e selecione Adicionar.
O arquivo NotePage.xaml será aberto em uma nova guia, exibindo toda a marcação XAML que representa a interface do usuário da página. Substitua a marcação de código XAML na seguinte marcação:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Notes.NotePage" Title="Note"> <VerticalStackLayout Spacing="10" Margin="5"> <Editor x:Name="TextEditor" Placeholder="Enter your note" HeightRequest="100" /> <Grid ColumnDefinitions="*,*" ColumnSpacing="4"> <Button Text="Save" Clicked="SaveButton_Clicked" /> <Button Grid.Column="1" Text="Delete" Clicked="DeleteButton_Clicked" /> </Grid> </VerticalStackLayout> </ContentPage>Salve o arquivo pressionando Ctrl+S ou selecionando o menu Salvar Arquivo>NotePage.xaml.
Vamos especificar as partes principais dos controles XAML colocados na página:
<VerticalStackLayout>organiza seus controles filhos verticalmente, um abaixo do outro.<Editor>é um controle de editor de texto de várias linhas e é o primeiro controle dentro de VerticalStackLayout.<Grid>é um controle de layout e é o segundo controle dentro de VerticalStackLayout.Esse controle define colunas e linhas para criar células. Os controles filho são colocados dentro dessas células.
Por padrão, o controle Grid contém uma única linha e coluna, criando uma única célula. As colunas são definidas com uma largura e o valor
*para largura informa à coluna para preencher o máximo de espaço possível. O snippet de código anterior definiu duas colunas, ambas usando o máximo de espaço possível, que distribui uniformemente as colunas no espaço alocado:ColumnDefinitions="*,*". Os tamanhos de coluna são separados por um caractere,.Colunas e linhas definidas por um Grid são indexadas a partir de 0. Portanto, a primeira coluna seria o índice 0, a segunda coluna é o índice 1 e assim por diante.
Dois controles
<Button>estão dentro do<Grid>e atribuídos a uma coluna. Se um controle filho não definir uma atribuição de coluna, ele será atribuído automaticamente à primeira coluna. Nesta marcação, o primeiro botão é o botão "Salvar" e atribuído automaticamente à primeira coluna, coluna 0. O segundo botão é o botão "Excluir" e atribuído à segunda coluna, coluna 1.Observe que os dois botões têm o evento
Clickedmanipulado. Você adicionará o código para esses manipuladores na próxima seção.
Carregar e salvar uma anotação
Abra o arquivo NotePage.xaml.cs code-behind. Você pode abrir o code-behind para o arquivo NotePage.xaml de três maneiras:
- Se o NotePage.xaml estiver aberto e for o documento ativo que está sendo editado, pressione F7.
- Se o NotePage.xaml estiver aberto e for o documento ativo que está sendo editado, clique com o botão direito do mouse no editor de texto e selecione Exibir Código.
- Use o Gerenciador de Soluções para expandir a entrada NotePage.xaml, revelando o arquivo NotePage.xaml.cs. Clique duas vezes no arquivo para abri-lo.
Quando você adiciona um novo arquivo XAML, o code-behind contém uma única linha no construtor, uma chamada ao método InitializeComponent:
namespace Notes;
public partial class NotePage : ContentPage
{
public NotePage()
{
InitializeComponent();
}
}
O método InitializeComponent lê a marcação XAML e inicializa todos os objetos definidos pela marcação. Os objetos são conectados em suas relações pai-filho e os manipuladores de eventos definidos no código são anexados a eventos definidos no XAML.
Agora que você entende um pouco mais sobre arquivos code-behind, você adicionará código ao arquivo NotePage.xaml.cs code-behind para lidar com o carregamento e salvamento de anotações.
Quando uma anotação é criada, ela é salva no dispositivo como um arquivo de texto. O nome do arquivo é representado pela variável
_fileName. Adicione a seguinte declaração de variávelstringà classeNotePage:public partial class NotePage : ContentPage { string _fileName = Path.Combine(FileSystem.AppDataDirectory, "notes.txt");O código acima constrói um caminho para o arquivo, armazenando-o no diretório de dados local do aplicativo. O nome do arquivo é notes.txt.
No construtor da classe, depois que o método
InitializeComponentfor chamado, leia o arquivo do dispositivo e armazene seu conteúdo na propriedadeTextEditordo controleText:public NotePage() { InitializeComponent(); if (File.Exists(_fileName)) TextEditor.Text = File.ReadAllText(_fileName); }Em seguida, adicione o código para lidar com os eventos de
Clickeddefinidos no XAML:private void SaveButton_Clicked(object sender, EventArgs e) { // Save the file. File.WriteAllText(_fileName, TextEditor.Text); } private void DeleteButton_Clicked(object sender, EventArgs e) { // Delete the file. if (File.Exists(_fileName)) File.Delete(_fileName); TextEditor.Text = string.Empty; }O método
SaveButton_Clickedgrava o texto no controle Editor, no arquivo representado pela variável_fileName.O método
DeleteButton_Clickedprimeiro verifica se o arquivo representado pela variável_fileNamee, se existir, o exclui. Em seguida, o texto do controle Editor é limpo.Salve o arquivo pressionando Ctrl+S ou selecionando o menu Salvar arquivo>NotePage.xaml.cs.
O código final do arquivo code-behind deve ser semelhante ao seguinte:
namespace Notes;
public partial class NotePage : ContentPage
{
string _fileName = Path.Combine(FileSystem.AppDataDirectory, "notes.txt");
public NotePage()
{
InitializeComponent();
if (File.Exists(_fileName))
TextEditor.Text = File.ReadAllText(_fileName);
}
private void SaveButton_Clicked(object sender, EventArgs e)
{
// Save the file.
File.WriteAllText(_fileName, TextEditor.Text);
}
private void DeleteButton_Clicked(object sender, EventArgs e)
{
// Delete the file.
if (File.Exists(_fileName))
File.Delete(_fileName);
TextEditor.Text = string.Empty;
}
}
Testar a anotação
Agora que página de notas está concluída, você precisa de uma maneira de apresentá-la ao usuário. Abra o arquivo AppShell.xaml e altere a primeira entrada ShellContent para apontar para o NotePage em vez de MainPage:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="Notes.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Notes">
<TabBar>
<ShellContent
Title="Notes"
ContentTemplate="{DataTemplate local:NotePage}"
Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />
<ShellContent
Title="About"
ContentTemplate="{DataTemplate local:AboutPage}"
Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
</TabBar>
</Shell>
Salve o arquivo e execute o aplicativo. Tente digitar na caixa de entrada e pressione o botão Salvar. Feche o aplicativo e reabra-o. A anotação inserida deve ser carregada do armazenamento do dispositivo.
Associar dados à interface do usuário e navegar em páginas
Esta parte do tutorial apresenta os conceitos de exibições, modelos e navegação no aplicativo.
Nas etapas anteriores do tutorial, você adicionou duas páginas ao projeto: NotePage e AboutPage. As páginas representam uma exibição de dados. O NotePage é uma "exibição" que exibe "dados de anotação" e o AboutPage é uma "exibição" que exibe "dados de informações do aplicativo". Ambas as exibições têm um modelo desses dados codificados ou inseridos neles, e você precisará separar o modelo de dados da exibição.
Qual é o benefício de separar o modelo da exibição? Ele permite que você projete a exibição para representar e interagir com qualquer parte do modelo sem se preocupar com o código real que implementa o modelo. Isso é feito usando a associação de dados, algo que será apresentado posteriormente neste tutorial. Por enquanto, porém, vamos reestruturar o projeto.
Separar a exibição e o modelo
Refatore o código existente para separar o modelo da exibição. As próximas etapas organizarão o código para que os modos de exibição e os modelos sejam definidos separadamente entre si.
Exclua MainPage.xaml e MainPage.xaml.cs do seu projeto, eles não são mais necessários. No painel Gerenciador de Soluções, localize a entrada para MainPage.xaml, clique com o botão direito do mouse e selecione Excluir.
Tip
Excluir o item MainPage.xaml também deve excluir o item MainPage.xaml.cs. Se MainPage.xaml.cs não tiver sido excluído, clique com o botão direito do mouse nele e selecione Excluir.
Clique com o botão direito no projeto Notes e selecione Adicionar>Nova Pasta. Nomeie a pasta Models.
Clique com o botão direito no projeto Notes e selecione Adicionar>Nova Pasta. Nomeie a pasta Views.
Localize o item NotePage.xaml e arraste-o para a pasta Views. O NotePage.xaml.cs deve se mover com ele.
Important
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 você vir este aviso.
O Visual Studio também pode perguntar se você deseja ajustar o namespace do arquivo movido. Selecione Não, pois as próximas etapas alterarão o namespace.
Localize o item AboutPage.xaml e arraste-o para a pasta Views. O AboutPage.xaml.cs deve se mover com ele.
Atualizar o namespace de exibição
Agora que as exibições foram movidas para a pasta Views, você precisará atualizar os namespaces para corresponder. O namespace para os arquivos XAML e code-behind das páginas é definido como Notes. Isso precisa ser atualizado para Notes.Views.
No painel Gerenciador de Soluções, expanda NotePage.xaml e AboutPage.xaml para revelar os arquivos code-behind:
Clique duas vezes no item NotePage.xaml.cs para abrir o editor de código. Altere o namespace para
Notes.Views:namespace Notes.Views;Repita as etapas anteriores do item AboutPage.xaml.cs.
Clique duas vezes no item NotePage.xaml para abrir o editor XAML. O namespace antigo é referenciado por meio do atributo
x:Class, que define qual tipo de classe é o code-behind do XAML. Essa entrada não é apenas o namespace, mas o namespace com o tipo. Altere o valorx:ClassparaNotes.Views.NotePage:x:Class="Notes.Views.NotePage"Repita a etapa anterior do item AboutPage.xaml, mas defina o valor
x:ClasscomoNotes.Views.AboutPage.
Corrigir a referência de namespace no Shell
O AppShell.xaml define duas guias, uma para o NotesPage e outra para AboutPage. Agora que essas duas páginas foram movidas para um novo namespace, o mapeamento de tipo no XAML agora é inválido. No painel Gerenciador de Soluções, clique duas vezes na entrada AppShell.xaml para abri-la no editor XAML. Ele deve se parecer com o seguinte snippet:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="Notes.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Notes">
<TabBar>
<ShellContent
Title="Notes"
ContentTemplate="{DataTemplate local:NotePage}"
Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />
<ShellContent
Title="About"
ContentTemplate="{DataTemplate local:AboutPage}"
Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
</TabBar>
</Shell>
Um namespace .NET é importado para o XAML por meio de uma declaração de namespace XML. Na marcação XAML anterior, é o atributo xmlns:local="clr-namespace:Notes" no elemento raiz: <Shell>. O formato de declarar um namespace XML para importar um namespace do .NET no mesmo assembly é:
xmlns:{XML namespace name}="clr-namespace:{.NET namespace}"
Portanto, a declaração anterior mapeia o namespace XML de local para o namespace .NET de Notes. É uma prática comum mapear o nome local para o namespace raiz do projeto.
Remova o namespace local XML e adicione um novo. Esse novo namespace XML será mapeado para o namespace do .NET de Notes.Views; portanto, nomeie-o views. A declaração deve ser semelhante ao seguinte atributo: xmlns:views="clr-namespace:Notes.Views".
O namespace XML local foi usado pelas propriedades ShellContent.ContentTemplate, altere-os para views. Seu XAML agora deve se parecer com o seguinte snippet:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="Notes.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Notes.Views">
<TabBar>
<ShellContent
Title="Notes"
ContentTemplate="{DataTemplate views:NotePage}"
Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />
<ShellContent
Title="About"
ContentTemplate="{DataTemplate views:AboutPage}"
Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
</TabBar>
</Shell>
Agora você deve ser capaz de executar o aplicativo sem erros do compilador e tudo ainda deve funcionar como antes.
Definir o modelo
Atualmente, o modelo são os dados inseridos na anotação e sobre exibições. Criaremos novas classes para representar esses dados. Primeiro, o modelo para representar os dados de uma página de anotação:
No painel Gerenciador de Soluções , clique com o botão direito do Models mouse na pasta e selecione Adicionar>Classe.
Nomeie a classe Note.cs e pressione Adicionar.
Abra Note.cs e substitua o código pelo seguinte snippet:
namespace Notes.Models; internal class Note { public string Filename { get; set; } public string Text { get; set; } public DateTime Date { get; set; } }Salve o arquivo.
Em seguida, crie o modelo da página sobre:
No painel Gerenciador de Soluções , clique com o botão direito do Models mouse na pasta e selecione Adicionar>Classe.
Nomeie a classe About.cs e pressione Adicionar.
Abra About.cs e substitua o código pelo seguinte snippet:
namespace Notes.Models; internal class About { public string Title => AppInfo.Name; public string Version => AppInfo.VersionString; public string MoreInfoUrl => "https://aka.ms/maui"; public string Message => "This app is written in XAML and C# with .NET MAUI."; }Salve o arquivo.
Página Atualizar Sobre
A página sobre será a página mais rápida a ser atualizada e você poderá executar o aplicativo e ver como ele carrega dados do modelo.
No painel Gerenciador de Soluções, abra o arquivo Views\AboutPage.xaml.
Substitua o conteúdo pelo seguinte snippet:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:models="clr-namespace:Notes.Models" x:Class="Notes.Views.AboutPage" x:DataType="models:About"> <ContentPage.BindingContext> <models:About /> </ContentPage.BindingContext> <VerticalStackLayout Spacing="10" Margin="10"> <HorizontalStackLayout Spacing="10"> <Image Source="dotnet_bot.png" SemanticProperties.Description="The dot net bot waving hello!" HeightRequest="64" /> <Label FontSize="22" FontAttributes="Bold" Text="{Binding Title}" VerticalOptions="End" /> <Label FontSize="22" Text="{Binding Version}" VerticalOptions="End" /> </HorizontalStackLayout> <Label Text="{Binding Message}" /> <Button Text="Learn more..." Clicked="LearnMore_Clicked" /> </VerticalStackLayout> </ContentPage>
Vamos examinar as linhas alteradas, que são realçadas no snippet anterior:
xmlns:models="clr-namespace:Notes.Models"Essa linha mapeia o namespace do .NET
Notes.Modelspara o namespace XMLmodels.x:DataType="models:About"Essa linha instrui o compilador XAML a compilar todas as expressões de associação para aumentar o desempenho do runtime e resolve as expressões de associação em relação ao
Notes.Models.Abouttipo.A propriedade
BindingContextdo ContentPage é definida como uma instância da classeNote.Models.About, usando o namespace XML e o objeto demodels:About. Isso foi definido usando sintaxe de elemento de propriedade em vez de um atributo XML.Important
Até agora, as propriedades foram definidas usando um atributo XML. Isso funciona bem para valores simples, como uma propriedade
Label.FontSize. Mas se o valor da propriedade for mais complexo, você deverá usar sintaxe do elemento de propriedade para criar o objeto. Considere o seguinte exemplo de criação de um rótulo com seu conjunto de propriedadesFontSize:<Label FontSize="22" />A mesma propriedade
FontSizepode ser definida usando sintaxe do elemento de propriedade:<Label> <Label.FontSize> 22 </Label.FontSize> </Label>Três controles
<Label>tiveram seu valor de propriedadeTextalterado de uma cadeia de caracteres codificada para uma sintaxe de associação:{Binding PATH}.A sintaxe
{Binding}é processada em tempo de execução, permitindo que o valor retornado da associação seja dinâmico. A partePATHde{Binding PATH}é o caminho de propriedade ao qual associar. A propriedade vem do controle atualBindingContext. Com o controle<Label>,BindingContextnão está definido. O contexto é herdado do pai quando não é definido pelo controle, o que, nesse caso, o contexto de configuração do objeto pai é o objeto raiz: ContentPage.O objeto no
BindingContexté uma instância do modeloAbout. O caminho de associação de um dos rótulos associa a propriedadeLabel.Textà propriedadeAbout.Title.
A última alteração na página sobre é atualizar o clique do botão que abre uma página da Web. A URL foi codificada no code-behind, mas a URL deve vir do modelo que está na propriedade BindingContext.
No painel Gerenciador de Soluções, abra o arquivo Views\AboutPage.xaml.cs.
Substitua o método
LearnMore_Clickedpelo seguinte código:private async void LearnMore_Clicked(object sender, EventArgs e) { if (BindingContext is Models.About about) { // Navigate to the specified URL in the system browser. await Launcher.Default.OpenAsync(about.MoreInfoUrl); } }
Se você observar a linha realçada, o código verificará se o BindingContext é um tipo Models.About e, se for, o atribuirá à variável about. A próxima linha dentro da instrução if abre o navegador para a URL fornecida pela propriedade about.MoreInfoUrl.
Execute o aplicativo e você verá que ele é executado exatamente da mesma forma que antes. Tente alterar os valores do modelo e veja como a interface do usuário e a URL abertas pelo navegador também são alteradas.
Página Atualizar Observação
A seção anterior vinculou o modo de exibição de página about ao modelo de about e agora você fará o mesmo, associando o modo de exibição note ao modelo note. No entanto, nesse caso, o modelo não será criado no XAML, mas será fornecido no code-behind nas próximas etapas.
No painel Gerenciador de Soluções, abra o arquivo Views\NotePage.xaml.
Substitua o conteúdo pelo seguinte snippet:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:models="clr-namespace:Notes.Models" x:Class="Notes.Views.NotePage" Title="Note" x:DataType="models:Note"> <VerticalStackLayout Spacing="10" Margin="5"> <Editor x:Name="TextEditor" Placeholder="Enter your note" Text="{Binding Text}" HeightRequest="100" /> <Grid ColumnDefinitions="*,*" ColumnSpacing="4"> <Button Text="Save" Clicked="SaveButton_Clicked" /> <Button Grid.Column="1" Text="Delete" Clicked="DeleteButton_Clicked" /> </Grid> </VerticalStackLayout> </ContentPage>
Vamos examinar as linhas alteradas, que são realçadas no snippet anterior:
xmlns:models="clr-namespace:Notes.Models"Essa linha mapeia o namespace do .NET
Notes.Modelspara o namespace XMLmodels.x:DataType="models:Note"Essa linha instrui o compilador XAML a compilar todas as expressões de associação para aumentar o desempenho do runtime e resolve as expressões de associação em relação ao
Notes.Models.Notetipo.Text="{Binding Text}"Essa linha altera o
<Editor>controle adicionando aTextpropriedade e associando a propriedade àTextpropriedade.
As modificações para o code-behind são mais complicadas do que o XAML. O código atual está carregando o conteúdo do arquivo no construtor e definindo-o diretamente para a propriedade TextEditor.Text. Aqui está a aparência do código atual:
public NotePage()
{
InitializeComponent();
if (File.Exists(_fileName))
TextEditor.Text = File.ReadAllText(_fileName);
}
Em vez de carregar a anotação no construtor, crie um novo método LoadNote. Esse método fará o seguinte:
- Aceite um parâmetro de nome de arquivo.
- Crie um novo modelo de anotação e defina o nome do arquivo.
- Se o arquivo existir, carregue seu conteúdo no modelo.
- Se o arquivo existir, atualize o modelo com a data em que o arquivo foi criado.
- Defina o
BindingContextda página como o modelo.
No painel Gerenciador de Soluções, abra o arquivo Views\NotePage.xaml.cs.
Adicione o seguinte método à classe :
private void LoadNote(string fileName) { Models.Note noteModel = new Models.Note(); noteModel.Filename = fileName; if (File.Exists(fileName)) { noteModel.Date = File.GetCreationTime(fileName); noteModel.Text = File.ReadAllText(fileName); } BindingContext = noteModel; }Atualize o construtor de classe para chamar
LoadNote. O nome do arquivo da anotação deve ser um nome gerado aleatoriamente para ser criado no diretório de dados local do aplicativo.public NotePage() { InitializeComponent(); string appDataPath = FileSystem.AppDataDirectory; string randomFileName = $"{Path.GetRandomFileName()}.notes.txt"; LoadNote(Path.Combine(appDataPath, randomFileName)); }
Adicionar uma exibição e um modelo que lista todas as anotações
Esta parte do tutorial adiciona a parte final do aplicativo, uma exibição que exibe todas as anotações criadas anteriormente.
Várias anotações e navegação
Atualmente, o modo de exibição de anotação exibe uma única anotação. Para exibir várias anotações, crie uma nova exibição e um modelo: AllNotes.
- No painel Gerenciador de Soluções , clique com o botão direito do Views mouse na pasta e selecione Adicionar>Novo Item
- Na caixa de diálogo Adicionar Novo Item, selecione .NET MAUI na lista de modelos no lado esquerdo da janela. Em seguida, selecione o modelo do .NET MAUI ContentPage (XAML). Nomeie o arquivo AllNotesPage.xaml e selecione Adicionar.
- No painel Gerenciador de Soluções , clique com o botão direito do Models mouse na pasta e selecione Adicionar>Classe
- Nomeie a classe AllNotes.cs e pressione Adicionar.
Codificar o modelo do AllNotes
O novo modelo representará os dados necessários para exibir várias anotações. Esses dados serão uma propriedade que representa uma coleção de anotações. A coleção será uma ObservableCollection que é uma coleção especializada. Quando um controle que lista vários itens, como um ListView, é associado a um ObservableCollection, os dois trabalham juntos para manter automaticamente a lista de itens em sincronia com a coleção. Se a lista adicionar um item, a coleção será atualizada. Se a coleção adicionar um item, o controle será atualizado automaticamente com um novo item.
No painel do Gerenciador de Soluções, abra o arquivo Models\AllNotes.cs.
Substitua o código pelo seguinte snippet:
using System.Collections.ObjectModel; namespace Notes.Models; internal class AllNotes { public ObservableCollection<Note> Notes { get; set; } = new ObservableCollection<Note>(); public AllNotes() => LoadNotes(); public void LoadNotes() { Notes.Clear(); // Get the folder where the notes are stored. string appDataPath = FileSystem.AppDataDirectory; // Use Linq extensions to load the *.notes.txt files. IEnumerable<Note> notes = Directory // Select the file names from the directory .EnumerateFiles(appDataPath, "*.notes.txt") // Each file name is used to create a new Note .Select(filename => new Note() { Filename = filename, Text = File.ReadAllText(filename), Date = File.GetLastWriteTime(filename) }) // With the final collection of notes, order them by date .OrderBy(note => note.Date); // Add each note into the ObservableCollection foreach (Note note in notes) Notes.Add(note); } }
O código anterior declara uma coleção, chamada Notes, e usa o método LoadNotes para carregar anotações do dispositivo. Esse método usa extensões LINQ para carregar, transformar e classificar os dados na coleção Notes.
Projetar a página AllNotes
Em seguida, o modo de exibição precisa ser projetado para dar suporte ao modelo AllNotes.
No painel Gerenciador de Soluções, abra o arquivo Views\AllNotesPage.xaml.
Substitua o código pela seguinte marcação:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:models="clr-namespace:Notes.Models" x:Class="Notes.Views.AllNotesPage" Title="Your Notes" x:DataType="models:AllNotes"> <!-- Add an item to the toolbar --> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" Clicked="Add_Clicked" IconImageSource="{FontImageSource Glyph='+', Color=Black, Size=22}" /> </ContentPage.ToolbarItems> <!-- Display notes in a list --> <CollectionView x:Name="notesCollection" ItemsSource="{Binding Notes}" Margin="20" SelectionMode="Single" SelectionChanged="notesCollection_SelectionChanged"> <!-- Designate how the collection of items are laid out --> <CollectionView.ItemsLayout> <LinearItemsLayout Orientation="Vertical" ItemSpacing="10" /> </CollectionView.ItemsLayout> <!-- Define the appearance of each item in the list --> <CollectionView.ItemTemplate> <DataTemplate x:DataType="models:Note"> <StackLayout> <Label Text="{Binding Text}" FontSize="22"/> <Label Text="{Binding Date}" FontSize="14" TextColor="Silver"/> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
O XAML anterior apresenta alguns novos conceitos:
A propriedade
ContentPage.ToolbarItemscontém umToolbarItem. Os botões definidos aqui geralmente são exibidos na parte superior do aplicativo, ao longo do título da página. Dependendo da plataforma, porém, ela pode estar em uma posição diferente. Quando um desses botões é pressionado, o eventoClickedé acionado, assim como um botão normal.A propriedade
ToolbarItem.IconImageSourcedefine o ícone a ser exibido no botão. O ícone pode ser qualquer recurso de imagem definido pelo projeto, no entanto, neste exemplo, umFontImageSourceé usado. UmFontImageSourcepode usar um único glifo de uma fonte como uma imagem.O controle CollectionView exibe uma coleção de itens e, nesse caso, está associado à propriedade
Notesdo modelo. A maneira como cada item é apresentado pelo modo de exibição de coleção é definida por meio das propriedadesCollectionView.ItemsLayouteCollectionView.ItemTemplate.Para cada item da coleção, o
CollectionView.ItemTemplategera o XAML declarado. OBindingContextdesse XAML torna-se o item de coleção em si, nesse caso, cada anotação individual. O modelo da anotação usa dois rótulos, que são associados às propriedadesTexteDateda nota.O CollectionView manipula o evento
SelectionChanged, que é gerado quando um item no modo de exibição de coleção é selecionado.
O code-behind para a exibição precisa ser gravado para carregar as anotações e manipular os eventos.
No painel Gerenciador de Soluções, abra o arquivo Views/AllNotesPage.xaml.cs.
Substitua o código pelo seguinte snippet:
namespace Notes.Views; public partial class AllNotesPage : ContentPage { public AllNotesPage() { InitializeComponent(); BindingContext = new Models.AllNotes(); } protected override void OnAppearing() { ((Models.AllNotes)BindingContext).LoadNotes(); } private async void Add_Clicked(object sender, EventArgs e) { await Shell.Current.GoToAsync(nameof(NotePage)); } private async void notesCollection_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.Count != 0) { // Get the note model var note = (Models.Note)e.CurrentSelection[0]; // Should navigate to "NotePage?ItemId=path\on\device\XYZ.notes.txt" await Shell.Current.GoToAsync($"{nameof(NotePage)}?{nameof(NotePage.ItemId)}={note.Filename}"); // Unselect the UI notesCollection.SelectedItem = null; } } }
Esse código usa o construtor para definir o BindingContext da página para o modelo.
O método OnAppearing é substituído da classe base. Esse método é chamado automaticamente sempre que a página é mostrada, como quando a página é navegada. O código aqui informa ao modelo para carregar as anotações. Como o CollectionView no modo de exibição AllNotes está vinculado à propriedade AllNotesNotes do modelo, que é um ObservableCollection, sempre que as notas são carregadas, o CollectionView é atualizado automaticamente.
O manipulador de Add_Clicked apresenta outro novo conceito, a navegação. Como o aplicativo está usando o Shell do .NET MAUI, você pode navegar até páginas chamando o método Shell.Current.GoToAsync. Observe que o manipulador é declarado com a palavra-chave async, que permite o uso da palavra-chave await ao navegar. Esse manipulador navega até o NotePage.
A última parte do código no snippet anterior é o manipulador de notesCollection_SelectionChanged. Esse método usa o item selecionado no momento, um modelo Note e usa suas informações para navegar até o NotePage.
GoToAsync usa uma cadeia de caracteres de URI para navegação. Nesse caso, uma cadeia de caracteres é construída que usa um parâmetro de cadeia de caracteres de consulta para definir uma propriedade na página de destino. A cadeia de caracteres interpolada que representa o URI acaba parecendo semelhante à seguinte cadeia de caracteres:
NotePage?ItemId=path\on\device\XYZ.notes.txt
O parâmetro ItemId= é definido como o nome do arquivo no dispositivo em que a anotação é armazenada.
O Visual Studio pode estar indicando que a propriedade NotePage.ItemId não existe, o que é correto. A próxima etapa é modificar a exibição Note para carregar o modelo com base no parâmetro ItemId que você criará.
Parâmetros de cadeia de caracteres de consulta
A exibição Note precisa dar suporte ao parâmetro de cadeia de caracteres de consulta, ItemId. Crie-o agora:
No painel Gerenciador de Soluções, abra o arquivo Views/NotePage.xaml.cs.
Adicione o atributo
QueryPropertyà palavra-chaveclass, fornecendo o nome da propriedade de cadeia de caracteres de consulta e a propriedade de classe para a qual ela mapeia,ItemIdeItemIdrespectivamente:[QueryProperty(nameof(ItemId), nameof(ItemId))] public partial class NotePage : ContentPageAdicione uma nova propriedade
stringchamadaItemId. Essa propriedade chama o métodoLoadNote, passando o valor da propriedade, que, por sua vez, deve ser o nome do arquivo da nota:public string ItemId { set { LoadNote(value); } }Substitua os manipuladores
SaveButton_ClickedeDeleteButton_Clickedpelo seguinte código:private async void SaveButton_Clicked(object sender, EventArgs e) { if (BindingContext is Models.Note note) File.WriteAllText(note.Filename, TextEditor.Text); await Shell.Current.GoToAsync(".."); } private async void DeleteButton_Clicked(object sender, EventArgs e) { if (BindingContext is Models.Note note) { // Delete the file. if (File.Exists(note.Filename)) File.Delete(note.Filename); } await Shell.Current.GoToAsync(".."); }Os botões agora são
async. Depois que eles são pressionados, a página navega de volta para a página anterior usando um URI de...Exclua a variável
_fileNameda parte superior do código, pois ela não é mais usada pela classe.
Modificar a árvore visual do aplicativo
O AppShell ainda está carregando a página de anotação única, em vez disso, ele precisa carregar a exibição AllPages. Abra o arquivo AppShell.xaml e altere a primeira entrada ShellContent para apontar para o AllNotesPage em vez de NotePage:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="Notes.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Notes.Views">
<TabBar>
<ShellContent
Title="Notes"
ContentTemplate="{DataTemplate views:AllNotesPage}"
Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />
<ShellContent
Title="About"
ContentTemplate="{DataTemplate views:AboutPage}"
Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
</TabBar>
</Shell>
Se você executar o aplicativo agora, perceberá que ele falhará se pressionar o botão Adicionar, reclamando que ele não pode navegar até NotesPage. Todas as páginas que podem ser navegadas de outra página precisam ser registradas no sistema de navegação. As páginas AllNotesPage e AboutPage são registradas automaticamente no sistema de navegação sendo declaradas no TabBar.
Registre o NotesPage com o sistema de navegação:
No painel Gerenciador de Soluções, abra o arquivo AppShell.xaml.cs.
Adicione uma linha ao construtor que registra a rota de navegação:
namespace Notes; public partial class AppShell : Shell { public AppShell() { InitializeComponent(); Routing.RegisterRoute(nameof(Views.NotePage), typeof(Views.NotePage)); } }
O método Routing.RegisterRoute usa dois parâmetros:
- O primeiro parâmetro é o nome da cadeia de caracteres do URI que você deseja registrar, nesse caso, o nome resolvido é
"NotePage". - O segundo parâmetro é o tipo de página a ser carregada quando
"NotePage"é navegada.
Agora você pode executar seu aplicativo. Tente adicionar novas anotações, navegar entre anotações e excluir anotações.
Explore o código deste tutorial.. Se você quiser baixar uma cópia do projeto concluído com a qual comparar seu código, baixe este projeto.
Você concluiu o tutorial Criar um aplicativo .NET MAUI!
Próximas etapas
No próximo tutorial, você aprenderá a implementar padrões MVVM (model-view-viewmodel) em seu projeto.
Os seguintes links fornecem mais informações relacionadas a alguns dos conceitos que você aprendeu neste tutorial: