Skapa en .NET MAUI-app
Den här självstudieserien är utformad för att visa hur du skapar en .NET Multi-platform App UI-app (.NET MAUI) som endast använder plattformsoberoende kod. Det innebär att koden du skriver inte är specifik för Windows, Android, iOS eller macOS. Appen som du skapar är en anteckningsapp där användaren kan skapa, spara och läsa in flera anteckningar.
I den här självstudien lär du dig att:
- Skapa en .NET MAUI Shell-app.
- Kör din app på din valda plattform.
- Definiera användargränssnittet med XAML (eXtensible Application Markup Language) och interagera med XAML-element via kod.
- Skapa vyer och binda dem till data.
- Använd navigering för att flytta till och från sidor.
Du använder Visual Studio 2022 för att skapa ett program där du kan ange en anteckning och spara den i enhetslagring. Det slutliga programmet visas nedan:
Skapa ett projekt
Innan du kan börja den här självstudien måste du följa Skapa din första appartikel. När du skapar projektet använder du följande inställningar:
projektnamn
Detta måste vara inställt på
Notes
. Om projektet heter något annat kan koden du kopierar och klistrar in från den här självstudien resultera i byggfel.Placera lösning och projekt i samma katalog
Avmarkera den här inställningen.
Välj det senaste .NET-ramverket när du skapar projektet.
Välj målenheten
.NET MAUI-appar är utformade för att köras på flera operativsystem och enheter. Du måste välja vilket mål du vill testa och felsöka appen med.
Ange Felsökningsmål i Visual Studio-verktygsfältet till den enhet som du vill felsöka och testa med. Följande steg visar hur du ställer in Felsökningsmål till Android:
- Välj listrutan Felsökningsmål.
- Välj Android-emulatorer objekt.
- Välj emulatorenheten.
Anpassa appgränssnittet
När Visual Studio skapar ett .NET MAUI-projekt genereras fyra viktiga kodfiler. Dessa visas i fönstret Solution Explorer i Visual Studio:
De här filerna hjälper dig att konfigurera och köra .NET MAUI-appen. Varje fil har ett annat syfte, som beskrivs nedan:
MauiProgram.cs
Det här är en kodfil som startar appen. Koden i den här filen fungerar som plattformsoberoende startpunkt för appen, som konfigurerar och startar appen. Startkoden för mallen pekar på den
App
-klass som definieras av App.xaml--filen.App.xaml och App.xaml.cs
För att hålla det enkelt kallas båda dessa filer för en enda fil. Det finns vanligtvis två filer med en XAML-fil, .xaml själva filen och en motsvarande kodfil som är ett underordnat objekt i Solution Explorer. Filen .xaml innehåller XAML-markering och kodfilen innehåller kod som skapats av användaren för att interagera med XAML-markering.
Filen App.xaml innehåller appomfattande XAML-resurser, till exempel färger, formatmallar eller mallar. Filen App.xaml.cs innehåller vanligtvis kod som instansierar Shell-programmet. I det här projektet pekar den på klassen
AppShell
.AppShell.xaml och AppShell.xaml.cs
Den här filen definierar klassen
AppShell
, som används för att definiera appens visuella hierarki.MainPage.xaml och MainPage.xaml.cs
Det här är startsidan som visas av appen. Filen MainPage.xaml definierar sidans användargränssnitt (användargränssnitt). MainPage.xaml.cs innehåller koden bakom för XAML, till exempel kod för en knappklickshändelse.
Lägg till en "om"-sida
Den första anpassningen du gör är att lägga till en annan sida i projektet. Den här sidan är en "om"-sida som representerar information om den här appen, till exempel författare, version och kanske en länk för mer information.
I fönstret Solution Explorer i Visual Studio högerklickar du på projektet Anteckningar>Lägg till>nytt objekt....
I dialogrutan Lägg till nytt objekt väljer du .NET MAUI- i malllistan till vänster i fönstret. Välj sedan mallen .NET MAUI ContentPage (XAML). Ge filen namnet AboutPage.xamloch välj sedan Lägg till.
Filen AboutPage.xaml öppnar en ny dokumentflik som visar alla XAML-markeringar som representerar sidans användargränssnitt. Ersätt XAML-markering med följande markering:
<?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>
Spara filen genom att trycka på CTRL+S- eller genom att välja menyn Arkiv>Spara AboutPage.xaml.
Nu ska vi dela upp de viktigaste delarna i XAML-kontrollerna som finns på sidan:
<ContentPage>
är rotobjektet för klassenAboutPage
.<VerticalStackLayout>
är det enda underordnade objektet i ContentPage. ContentPage kan bara ha ett underordnat objekt. Den VerticalStackLayout typen kan ha flera underordnade. Den här layoutkontrollen ordnar underordnade objekt lodrätt, en efter en.<HorizontalStackLayout>
fungerar på samma sätt som en<VerticalStackLayout>
, förutom att dess underordnade objekt är ordnade vågrätt.<Image>
visar en bild använder den i det här fallet dendotnet_bot.png
bild som medföljer varje .NET MAUI-projekt.Viktig
Filen som läggs till i projektet är faktiskt
dotnet_bot.svg
. .NET MAUI konverterar SVG-filer (Scalable Vector Graphics) till PNG-filer (Portable Network Graphic) baserat på målenheten. När du lägger till en SVG-fil i ditt .NET MAUI-appprojekt bör den därför refereras från XAML eller C# med ett.png
-tillägg. Den enda referensen till SVG-filen ska finnas i projektfilen.<Label>
kontroller visar text.<Button>
kontroller kan tryckas på av användaren, vilket genererar händelsenClicked
. Du kan köra kod som svar på händelsenClicked
.Clicked="LearnMore_Clicked"
Knappens
Clicked
händelse tilldelas tillLearnMore_Clicked
händelsehanteraren, som definieras i filen bakom koden. Du skapar den här koden i nästa steg.
Hantera händelsen Klickad
Nästa steg är att lägga till koden för knappens Clicked
händelse.
I fönstret Solution Explorer i Visual Studio expanderar du filen AboutPage.xaml för att visa filen bakom koden AboutPage.xaml.cs. Dubbelklicka sedan på filen AboutPage.xaml.cs för att öppna den i kodredigeraren.
Lägg till följande
LearnMore_Clicked
händelsehanterarkod, som öppnar systemwebbläsaren till en specifik URL: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"); }
Observera att nyckelordet
async
har lagts till i metoddeklarationen, vilket gör det möjligt att använda nyckelordetawait
när du öppnar systemwebbläsaren.Spara filen genom att trycka på CTRL+S- eller genom att välja menyn Arkiv>Spara AboutPage.xaml.cs.
Nu när XAML och bakomliggande kod för AboutPage
har slutförts måste du se till att det visas i appen.
Lägga till avbildningsresurser
Vissa kontroller kan använda bilder, vilket förbättrar hur användare interagerar med din app. I det här avsnittet laddar du ned två bilder som du använder i din app, tillsammans med två alternativa bilder för användning med iOS.
Ladda ned följande bilder:
ikon: Om
Den här bilden används som en ikon för den om-sida som du skapade tidigare.-ikon: Anteckningar
Den här bilden används som en ikon för anteckningssidan som du skapar i nästa del av den här självstudien.
När du har laddat ned bilderna kan du flytta dem med Utforskaren till mappen Resources\Images i projektet. Alla filer i den här mappen ingår automatiskt i projektet som en MauiImage- resurs. Du kan också använda Visual Studio för att lägga till bilderna i projektet. Om du flyttar bilderna för hand hoppar du över följande procedur.
Viktig
Hoppa inte över att ladda ned iOS-specifika bilder. De måste slutföra den här självstudien.
Flytta bilderna med Visual Studio
I fönstret Solution Explorer i Visual Studio expanderar du mappen Resources, som visar mappen Images.
Dricks
Du kan använda Utforskaren för att dra och släppa bilderna direkt i Solution Explorer-fönstret, ovanpå mappen Images. Detta flyttar automatiskt filerna till mappen och inkluderar dem i projektet. Om du väljer att dra och släppa filerna ignorerar du resten av den här proceduren.
Högerklicka på Bilder och välj Lägg till>befintligt objekt....
Navigera till mappen som innehåller de nedladdade bilderna.
Ändra filtret till filtypsfiltret till Image Files.
Håll ned CTRL- och klicka på var och en av bilderna som du laddade ned och tryck sedan på Lägg till
Ändra appgränssnittet
Som vi noterade i början av den här artikeln definierar klassen AppShell
en apps visuella hierarki, XAML-markering som används för att skapa appens användargränssnitt. Uppdatera XAML för att lägga till en TabBar kontroll:
Dubbelklicka på filen AppShell.xaml i fönstret Solution Explorer för att öppna XAML-redigeraren. Ersätt XAML-markering med följande kod:
<?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" Shell.FlyoutBehavior="Disabled"> <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>
Spara filen genom att trycka på CTRL+S- eller genom att välja menyn Arkiv>Spara AppShell.xaml.
Nu ska vi dela upp de viktigaste delarna i XAML:
-
<Shell>
är rotobjektet för XAML-markering. -
<TabBar>
är innehållet i Shell. - Två
<ShellContent>
objekt inuti<TabBar>
. Innan du ersatte mallkoden fanns det ett enda<ShellContent>
objekt som pekade på sidanMainPage
.
TabBar
och dess underordnade objekt representerar inte några användargränssnittselement, utan snarare organisationen av appens visuella hierarki. Shell tar dessa objekt och skapar användargränssnittet för innehållet, med ett fält högst upp som representerar varje sida. Egenskapen ShellContent.Icon
för varje sida använder tillägget OnPlatform
markering. Det här XAML-markeringstillägget används för att ange olika värden för olika plattformar. I det här exemplet använder varje plattform icon_about.png
-ikonen som standard, men iOS och MacCatalyst använder icon_about_ios.png
.
Varje <ShellContent>
objekt pekar på en sida som ska visas. Detta anges av egenskapen ContentTemplate
.
Kör appen
Kör appen genom att trycka på F5 eller trycka på uppspelningsknappen överst i Visual Studio:
Du ser att det finns två flikar: Anteckningar och Om. Tryck på fliken Om så navigerar appen till AboutPage
du skapade. Tryck på knappen Läs mer... för att öppna webbläsaren.
Stäng appen och gå tillbaka till Visual Studio. Om du använder Android-emulatorn avslutar du appen på den virtuella enheten eller trycker på stoppknappen överst i Visual Studio:
Skapa en sida för en anteckning
Nu när appen innehåller MainPage
och AboutPage
kan du börja skapa resten av appen. Först skapar du en sida som gör att en användare kan skapa och visa anteckningar, och sedan skriver du koden för att läsa in och spara anteckningen.
Anteckningssidan visar anteckningen och gör att du kan spara eller ta bort den. Lägg först till den nya sidan i projektet:
I fönstret Solution Explorer i Visual Studio högerklickar du på projektet Anteckningar>Lägg till>nytt objekt....
I dialogrutan Lägg till nytt objekt väljer du .NET MAUI- i malllistan till vänster i fönstret. Välj sedan mallen .NET MAUI ContentPage (XAML). Ge filen namnet NotePage.xamloch välj sedan Lägg till.
Filen NotePage.xaml öppnas på en ny flik och visar alla XAML-markeringar som representerar sidans användargränssnitt. Ersätt XAML-kodmarkeringen med följande markering:
<?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>
Spara filen genom att trycka på CTRL + S eller genom att välja menyn Arkiv>Spara NotePage.xaml.
Nu ska vi dela upp de viktigaste delarna i XAML-kontrollerna som finns på sidan:
<VerticalStackLayout>
ordnar sina underordnade kontroller lodrätt, en under den andra.<Editor>
är en textredigerare med flera rader och är den första kontrollen i VerticalStackLayout.<Grid>
är en layoutkontroll och är den andra kontrollen i VerticalStackLayout.Den här kontrollen definierar kolumner och rader för att skapa celler. Underordnade kontroller placeras i dessa celler.
Som standard innehåller Grid-kontrollen en enda rad och kolumn, vilket skapar en enda cell. Kolumner definieras med en bredd och
*
värdet för bredd gör att kolumnen fyller upp så mycket utrymme som möjligt. Det tidigare kodfragmentet definierade två kolumner, som båda använder så mycket utrymme som möjligt, vilket jämnt distribuerar kolumnerna i det tilldelade utrymmet:ColumnDefinitions="*,*"
. Kolumnstorlekarna avgränsas med ett,
tecken.Kolumner och rader som definieras av en Grid indexeras från och med 0. Så den första kolumnen skulle vara index 0, den andra kolumnen är index 1 och så vidare.
Två
<Button>
kontroller finns i<Grid>
och tilldelas en kolumn. Om en underordnad kontroll inte definierar en kolumntilldelning tilldelas den automatiskt till den första kolumnen. I den här markeringen är den första knappen knappen "Spara" och tilldelas automatiskt till den första kolumnen, kolumn 0. Den andra knappen är knappen "Ta bort" och tilldelad till den andra kolumnen, kolumn 1.Observera att de två knapparna har
Clicked
händelse hanterad. Du lägger till koden för dessa hanterare i nästa avsnitt.
Läsa in och spara en anteckning
Öppna filen NotePage.xaml.cs code-behind. Du kan öppna koden bakom för filen NotePage.xaml på tre sätt:
- Om NotePage.xaml är öppen och är det aktiva dokument som redigeras trycker du på F7.
- Om NotePage.xaml- är öppen och är det aktiva dokument som redigeras högerklickar du i textredigeraren och väljer Visa kod.
- Använd Solution Explorer- för att expandera posten NotePage.xaml och visa filen NotePage.xaml.cs. Dubbelklicka på filen för att öppna den.
När du lägger till en ny XAML-fil innehåller koden bakom en enda rad i konstruktorn, ett anrop till metoden InitializeComponent
:
namespace Notes;
public partial class NotePage : ContentPage
{
public NotePage()
{
InitializeComponent();
}
}
Metoden InitializeComponent
läser XAML-markering och initierar alla objekt som definieras av markering. Objekten är anslutna i sina överordnade och underordnade relationer, och de händelsehanterare som definierats i kod kopplas till händelser som anges i XAML.
Nu när du förstår lite mer om kod bakom filer lägger du till kod i den NotePage.xaml.cs bakomliggande filen för att hantera inläsning och sparande av anteckningar.
När en anteckning skapas sparas den på enheten som en textfil. Namnet på filen representeras av variabeln
_fileName
. Lägg till följandestring
variabeldeklaration i klassenNotePage
:public partial class NotePage : ContentPage { string _fileName = Path.Combine(FileSystem.AppDataDirectory, "notes.txt");
Koden ovan konstruerar en sökväg till filen och lagrar den i appens lokala datakatalog. Filnamnet är notes.txt.
När
InitializeComponent
-metoden anropas i konstruktorn av klassen läser du filen från enheten och lagrar dess innehåll iTextEditor
-kontrollens egenskapText
:public NotePage() { InitializeComponent(); if (File.Exists(_fileName)) TextEditor.Text = File.ReadAllText(_fileName); }
Lägg sedan till koden för att hantera de
Clicked
händelser som definierats i 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; }
Metoden
SaveButton_Clicked
skriver texten i kontrollen Editor till filen som representeras av variabeln_fileName
.Metoden
DeleteButton_Clicked
kontrollerar först om filen som representeras av variabeln_fileName
och om den finns tar den bort. Därefter rensas Editor-kontrollens text.Spara filen genom att trycka på CTRL + S eller genom att välja menyn Arkiv>Spara NotePage.xaml.cs.
Den sista koden för filen bakom koden bör se ut så här:
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;
}
}
Testa anteckningen
Nu när anteckningssidan är klar behöver du ett sätt att presentera den för användaren. Öppna filen AppShell.xaml och ändra den första posten ShellContent så att den pekar på NotePage
i stället för 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"
Shell.FlyoutBehavior="Disabled">
<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>
Spara filen och kör appen. Prova att skriva i postrutan och tryck på knappen Spara. Stäng appen och öppna den igen. Den angivna anteckningen ska läsas in från enhetens lagring.
Binda data till användargränssnittet och navigera på sidor
Den här delen av självstudien beskriver begreppen vyer, modeller och navigering i appen.
I föregående steg i självstudien lade du till två sidor i projektet: NotePage
och AboutPage
. Sidorna representerar en vy över data.
NotePage
är en "vy" som visar "anteckningsdata" och AboutPage
är en "vy" som visar "appinformationsdata". Båda dessa vyer har en modell av dessa data hårdkodade eller inbäddade i dem, och du måste separera datamodellen från vyn.
Vad är fördelen med att separera modellen från vyn? Det gör att du kan utforma vyn så att den representerar och interagerar med någon del av modellen utan att behöva bekymra dig om den faktiska koden som implementerar modellen. Detta görs med hjälp av databindning, något som kommer att visas senare i den här självstudien. För tillfället kan dock omstrukturera projektet.
Avgränsa vyn och modellen
Omstrukturera den befintliga koden för att separera modellen från vyn. Följande steg ordnar koden så att vyer och modeller definieras separat från varandra.
Ta bort MainPage.xaml- och MainPage.xaml.cs från projektet behövs de inte längre. I fönstret Solution Explorer letar du reda på posten för MainPage.xaml, högerklickar på den och väljer Ta bort.
Dricks
Om du tar bort MainPage.xaml objekt bör du också ta bort MainPage.xaml.cs objektet. Om MainPage.xaml.cs inte har tagits bort högerklickar du på den och väljer Ta bort.
Högerklicka på projektet Notes och välj Lägg till>ny mapp. Ge mappen namnet Models.
Högerklicka på projektet Notes och välj Lägg till>ny mapp. Ge mappen namnet Views.
Leta upp NotePage.xaml- objekt och dra det till mappen Views. Den NotePage.xaml.cs bör flytta med den.
Viktig
När du flyttar en fil uppmanar Visual Studio dig vanligtvis med en varning om hur flyttåtgärden kan ta lång tid. Detta bör inte vara ett problem här, tryck på OK om du ser den här varningen.
Visual Studio kan också fråga dig om du vill justera namnområdet för den flyttade filen. Välj Ingen eftersom nästa steg ändrar namnområdet.
Leta upp AboutPage.xaml- objekt och dra det till mappen Views. Den AboutPage.xaml.cs bör flytta med den.
Uppdatera visningsnamnområdet
Nu när vyerna har flyttats till mappen Views måste du uppdatera namnrymderna så att de matchar. Namnområdet för XAML- och kod bakom-filerna på sidorna är inställt på Notes
. Detta måste uppdateras till Notes.Views
.
I fönstret Solution Explorer expanderar du både NotePage.xaml och AboutPage.xaml för att visa filerna bakom koden:
Dubbelklicka på det NotePage.xaml.cs objektet för att öppna kodredigeraren. Ändra namnområdet till
Notes.Views
:namespace Notes.Views;
Upprepa föregående steg för det AboutPage.xaml.cs objektet.
Dubbelklicka på objektet NotePage.xaml för att öppna XAML-redigeraren. Det gamla namnområdet refereras via attributet
x:Class
, som definierar vilken klasstyp som är kod bakom för XAML. Den här posten är inte bara namnområdet, utan namnområdet med typen . Ändra värdet förx:Class
tillNotes.Views.NotePage
:x:Class="Notes.Views.NotePage"
Upprepa föregående steg för objektet AboutPage.xaml, men ange värdet
x:Class
tillNotes.Views.AboutPage
.
Åtgärda namnområdesreferensen i Shell
AppShell.xaml- definierar två flikar, en för NotesPage
och en annan för AboutPage
. Nu när dessa två sidor har flyttats till ett nytt namnområde är typmappningen i XAML nu ogiltig. I fönstret Solution Explorer dubbelklickar du på posten AppShell.xaml för att öppna den i XAML-redigeraren. Det bör se ut som följande kodfragment:
<?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"
Shell.FlyoutBehavior="Disabled">
<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>
Ett .NET-namnområde importeras till XAML via en XML-namnområdesdeklaration. I föregående XAML-markering är det attributet xmlns:local="clr-namespace:Notes"
i rotelementet: <Shell>
. Formatet för att deklarera ett XML-namnområde för att importera ett .NET-namnområde i samma sammansättning är:
xmlns:{XML namespace name}="clr-namespace:{.NET namespace}"
Den föregående deklarationen mappar därför XML-namnområdet för local
till .NET-namnområdet för Notes
. Det är vanligt att mappa namnet local
till projektets rotnamnområde.
Ta bort local
XML-namnområdet och lägg till ett nytt. Det nya XML-namnområdet mappas till .NET-namnområdet för Notes.Views
, så ge det namnet views
. Deklarationen bör se ut som följande attribut: xmlns:views="clr-namespace:Notes.Views"
.
local
XML-namnområdet användes av egenskaperna ShellContent.ContentTemplate
och ändrar dem till views
. Din XAML bör nu se ut som följande kodfragment:
<?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"
Shell.FlyoutBehavior="Disabled">
<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>
Nu bör du kunna köra appen utan kompilatorfel, och allt bör fortfarande fungera som tidigare.
Definiera modellen
För närvarande är modellen de data som är inbäddade i anteckningen och om vyer. Vi skapar nya klasser som representerar dessa data. Först modellen som representerar en anteckningssidas data:
I fönstret Solution Explorer högerklickar du på mappen Models och väljer Lägg till>klass....
Ge klassen namnet Note.cs och tryck på Lägg till.
Öppna Note.cs och ersätt koden med följande kodfragment:
namespace Notes.Models; internal class Note { public string Filename { get; set; } public string Text { get; set; } public DateTime Date { get; set; } }
Spara filen.
Skapa sedan om sidans modell:
I fönstret Solution Explorer högerklickar du på mappen Models och väljer Lägg till>klass....
Ge klassen namnet About.cs och tryck på Lägg till.
Öppna About.cs och ersätt koden med följande kodfragment:
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."; }
Spara filen.
Uppdatera om-sidan
Om-sidan blir den snabbaste sidan att uppdatera och du kan köra appen och se hur den läser in data från modellen.
I fönstret Solution Explorer öppnar du Views\AboutPage.xaml-filen.
Ersätt innehållet med följande kodfragment:
<?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"> <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>
Nu ska vi titta på de ändrade raderna, som är markerade i föregående kodfragment:
xmlns:models="clr-namespace:Notes.Models"
Den här raden mappar
Notes.Models
.NET-namnområde tillmodels
XML-namnområde.Egenskapen
BindingContext
för ContentPage är inställd på en instans av klassenNote.Models.About
med hjälp av XML-namnområdet och objektet förmodels:About
. Detta angavs med egenskapselementsyntax i stället för ett XML-attribut.Viktig
Hittills har egenskaper angetts med hjälp av ett XML-attribut. Detta fungerar bra för enkla värden, till exempel en
Label.FontSize
egenskap. Men om egenskapsvärdet är mer komplext måste du använda egenskapselementsyntax för att skapa objektet. Tänk dig följande exempel på hur du skapar en etikett med dessFontSize
egenskapsuppsättning:<Label FontSize="22" />
Samma
FontSize
egenskap kan anges med egenskapselementsyntax:<Label> <Label.FontSize> 22 </Label.FontSize> </Label>
Tre
<Label>
kontroller fickText
egenskapsvärdet ändrat från en hårdkodad sträng till bindningssyntax:{Binding PATH}
.{Binding}
syntax bearbetas vid körning, vilket gör att värdet som returneras från bindningen kan vara dynamiskt. DenPATH
delen av{Binding PATH}
är egenskapssökvägen som ska bindas till. Egenskapen kommer från den aktuella kontrollensBindingContext
. Med<Label>
kontroll tasBindingContext
inte upp. Kontexten ärvs från den överordnade när den tas bort av kontrollen, vilket i det här fallet den överordnade objektinställningskontexten är rotobjektet: ContentPage.Objektet i
BindingContext
är en instans avAbout
-modellen. Bindningssökvägen för en av etiketterna binder egenskapenLabel.Text
till egenskapenAbout.Title
.
Den sista ändringen av om-sidan uppdaterar knappklicket som öppnar en webbsida. URL:en hårdkodades i koden bakom, men URL:en ska komma från modellen som finns i egenskapen BindingContext
.
I fönstret Solution Explorer öppnar du filen Views\AboutPage.xaml.cs.
Ersätt metoden
LearnMore_Clicked
med följande kod: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); } }
Om du tittar på den markerade raden kontrollerar koden om BindingContext
är en Models.About
typ, och i så fall tilldelar den till variabeln about
. Nästa rad i if
-instruktionen öppnar webbläsaren till url:en som tillhandahålls av egenskapen about.MoreInfoUrl
.
Kör appen så bör du se att den körs på exakt samma sätt som tidigare. Prova att ändra om modellens värden och se hur användargränssnittet och URL:en som öppnas av webbläsaren också ändras.
Uppdatera anteckningssida
I föregående avsnitt kopplades about-sidvyn till about modell, och nu ska du göra samma sak och binda note-vyn till note-modellen. Men i det här fallet kommer modellen inte att skapas i XAML, men kommer att anges i koden bakom i de närmaste stegen.
I fönstret Solution Explorer öppnar du filen Views\NotePage.xaml.
Ändra
<Editor>
-kontrollen genom att lägga till egenskapenText
. Binda egenskapen till egenskapenText
:<Editor ... Text="{Binding Text}"
:<?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.Views.NotePage" Title="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>
Ändringarna för koden bakom är mer komplicerade än XAML. Den aktuella koden läser in filinnehållet i konstruktorn och ställer sedan in det direkt på egenskapen TextEditor.Text
. Så här ser den aktuella koden ut:
public NotePage()
{
InitializeComponent();
if (File.Exists(_fileName))
TextEditor.Text = File.ReadAllText(_fileName);
}
I stället för att läsa in anteckningen i konstruktorn skapar du en ny LoadNote
metod. Den här metoden gör följande:
- Acceptera en filnamnsparameter.
- Skapa en ny anteckningsmodell och ange filnamnet.
- Om filen finns läser du in dess innehåll i modellen.
- Om filen finns uppdaterar du modellen med det datum då filen skapades.
- Ange sidans
BindingContext
till modellen.
Öppna filen Views\NotePage.xaml.cs i Solution Explorer.
Lägg till följande metod i klassen:
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; }
Uppdatera klasskonstruktorn för att anropa
LoadNote
. Filnamnet för anteckningen ska vara ett slumpmässigt genererat namn som ska skapas i appens lokala datakatalog.public NotePage() { InitializeComponent(); string appDataPath = FileSystem.AppDataDirectory; string randomFileName = $"{Path.GetRandomFileName()}.notes.txt"; LoadNote(Path.Combine(appDataPath, randomFileName)); }
Lägg till en vy och modell som visar alla anteckningar
Den här delen av självstudien lägger till den sista delen av appen, en vy som visar alla anteckningar som skapats tidigare.
Flera anteckningar och navigering
För närvarande visar den anteckningen vyn en enda anteckning. Om du vill visa flera anteckningar skapar du en ny vy och modell: AllNotes.
- Högerklicka på mappen Views i Solution Explorer och välj Lägg till>nytt objekt...
- I dialogrutan Lägg till nytt objekt väljer du .NET MAUI- i malllistan till vänster i fönstret. Välj sedan mallen .NET MAUI ContentPage (XAML). Ge filen namnet AllNotesPage.xamloch välj sedan Lägg till.
- I fönstret Solution Explorer högerklickar du på mappen Models och väljer Lägg till>klass...
- Ge klassen namnet AllNotes.cs och tryck på Lägg till.
Koda AllNotes-modellen
Den nya modellen representerar de data som krävs för att visa flera anteckningar. Dessa data är en egenskap som representerar en samling anteckningar. Samlingen är en ObservableCollection
som är en specialiserad samling. När en kontroll som visar flera objekt, till exempel en ListView, är bunden till en ObservableCollection
, arbetar de två tillsammans för att automatiskt hålla listan över objekt synkroniserade med samlingen. Om listan lägger till ett objekt uppdateras samlingen. Om samlingen lägger till ett objekt uppdateras kontrollen automatiskt med ett nytt objekt.
I fönstret Solution Explorer öppnar du filen Models\AllNotes.cs.
Ersätt koden med följande kodfragment:
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); } }
Den tidigare koden deklarerar en samling med namnet Notes
och använder metoden LoadNotes
för att läsa in anteckningar från enheten. Den här metoden använder LINQ-tillägg för att läsa in, transformera och sortera data i den Notes
samlingen.
Utforma sidan AllNotes
Därefter måste vyn utformas för att stödja AllNotes-modellen.
I fönstret Solution Explorer öppnar du filen Views\AllNotesPage.xaml.
Ersätt koden med följande markering:
<?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.Views.AllNotesPage" Title="Your Notes"> <!-- Add an item to the toolbar --> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" Clicked="Add_Clicked" IconImageSource="{FontImage 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> <StackLayout> <Label Text="{Binding Text}" FontSize="22"/> <Label Text="{Binding Date}" FontSize="14" TextColor="Silver"/> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
Den tidigare XAML introducerar några nya begrepp:
Egenskapen
ContentPage.ToolbarItems
innehåller enToolbarItem
. Knapparna som definieras här visas vanligtvis överst i appen, längs sidrubriken. Beroende på plattform kan det dock vara i en annan position. När en av dessa knappar trycks in aktiveras denClicked
händelsen, precis som en normal knapp.Egenskapen
ToolbarItem.IconImageSource
anger ikonen som ska visas på knappen. Ikonen kan vara vilken bildresurs som helst som definieras av projektet, men i det här exemplet används enFontImage
. EnFontImage
kan använda ett enda tecken från ett teckensnitt som en bild.Kontrollen CollectionView visar en samling objekt och är i det här fallet bunden till modellens egenskap
Notes
. Hur varje objekt visas i samlingsvyn anges via egenskapernaCollectionView.ItemsLayout
ochCollectionView.ItemTemplate
.För varje objekt i samlingen genererar
CollectionView.ItemTemplate
den deklarerade XAML. DenBindingContext
av XAML blir själva samlingsobjektet, i det här fallet varje enskild anteckning. Mallen för anteckningen använder två etiketter som är bundna till anteckningensText
ochDate
egenskaper.CollectionView hanterar händelsen
SelectionChanged
, som utlöses när ett objekt i samlingsvyn väljs.
Koden bakom för vyn måste skrivas för att läsa in anteckningarna och hantera händelserna.
Öppna filen Views/AllNotesPage.xaml.cs i Solution Explorer.
Ersätt koden med följande kodfragment:
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; } } }
Den här koden använder konstruktorn för att ange sidans BindingContext
till modellen.
Metoden OnAppearing
åsidosättas från basklassen. Den här metoden anropas automatiskt när sidan visas, till exempel när sidan navigeras till. Koden här instruerar modellen att läsa in anteckningarna. Eftersom CollectionView i AllNotes-vyn är bunden till AllNotes-modellens egenskapNotes
, vilket är en ObservableCollection
, när anteckningarna läses in uppdateras CollectionView automatiskt.
Hanteraren Add_Clicked
introducerar ett annat nytt begrepp, navigering. Eftersom appen använder .NET MAUI Shell kan du navigera till sidor genom att anropa metoden Shell.Current.GoToAsync
. Observera att hanteraren deklareras med nyckelordet async
, vilket gör det möjligt att använda nyckelordet await
när du navigerar. Den här hanteraren navigerar till NotePage
.
Den sista koddelen i föregående kodfragment är notesCollection_SelectionChanged
-hanteraren. Den här metoden tar det markerade objektet, en Note modell, och använder sin information för att navigera till NotePage
.
GoToAsync använder en URI-sträng för navigering. I det här fallet skapas en sträng som använder en frågesträngsparameter för att ange en egenskap på målsidan. Den interpolerade strängen som representerar URI:n ser ut ungefär så här:
NotePage?ItemId=path\on\device\XYZ.notes.txt
Parametern ItemId=
anges till filnamnet på enheten där anteckningen lagras.
Visual Studio kan indikera att egenskapen NotePage.ItemId
inte finns, vilket den inte gör. Nästa steg är att ändra Note-vyn för att läsa in modellen baserat på den ItemId
parameter som du skapar.
Frågesträngsparametrar
Note-vyn måste ha stöd för frågesträngsparametern ItemId
. Skapa den nu:
Öppna filen Views/NotePage.xaml.cs i Solution Explorer.
Lägg till attributet
QueryProperty
i nyckelordetclass
, ange namnet på frågesträngsegenskapen och klassegenskapen som den mappar till,ItemId
respektiveItemId
:[QueryProperty(nameof(ItemId), nameof(ItemId))] public partial class NotePage : ContentPage
Lägg till en ny egenskap för
string
med namnetItemId
. Den här egenskapen anropar metodenLoadNote
och skickar värdet för egenskapen, som i sin tur ska vara filnamnet på anteckningen:public string ItemId { set { LoadNote(value); } }
Ersätt
SaveButton_Clicked
- ochDeleteButton_Clicked
-hanterare med följande kod: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(".."); }
Knapparna är nu
async
. När de har tryckts på navigerar sidan tillbaka till föregående sida med hjälp av en URI för..
.Ta bort variabeln
_fileName
överst i koden eftersom den inte längre används av klassen.
Ändra appens visuella träd
AppShell
läser fortfarande in den enkla anteckningssidan, i stället måste den läsa in AllPages-vyn. Öppna filen AppShell.xaml och ändra den första posten ShellContent så att den pekar på AllNotesPage
i stället för 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"
Shell.FlyoutBehavior="Disabled">
<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>
Om du kör appen nu ser du att den kraschar om du trycker på knappen Lägg till och klagar på att den inte kan gå till NotesPage
. Varje sida som kan navigeras till från en annan sida måste registreras med navigeringssystemet. Sidorna AllNotesPage
och AboutPage
registreras automatiskt i navigeringssystemet genom att deklareras i TabBar.
Registrera NotesPage
med navigeringssystemet:
I fönstret Solution Explorer öppnar du filen AppShell.xaml.cs.
Lägg till en rad i konstruktorn som registrerar navigeringsvägen:
namespace Notes; public partial class AppShell : Shell { public AppShell() { InitializeComponent(); Routing.RegisterRoute(nameof(Views.NotePage), typeof(Views.NotePage)); } }
Metoden Routing.RegisterRoute
tar två parametrar:
- Den första parametern är strängnamnet för den URI som du vill registrera, i det här fallet är det lösta namnet
"NotePage"
. - Den andra parametern är den typ av sida som ska läsas in när
"NotePage"
navigeras till.
Nu kan du köra din app. Prova att lägga till nya anteckningar, navigera fram och tillbaka mellan anteckningar och ta bort anteckningar.
Utforska koden för den här självstudien.. Om du vill ladda ned en kopia av det slutförda projektet för att jämföra koden med laddar du ned det här projektet.
Grattis!
Du har slutfört självstudien Skapa en .NET MAUI-app!
Nästa steg
I nästa del av självstudieserien får du lära dig hur du implementerar MVVM-mönster (model-view-viewmodel) i projektet.
Följande länkar innehåller mer information om några av de begrepp som du har lärt dig i den här självstudien:
Har du ett problem med det här avsnittet? Ge oss då feedback så att vi kan förbättra avsnittet.