Aplikacje mobilne · Nawigacja
Nawigacja I: NavigationPage i okna modalne
Rzadko aplikacja mobilna ma jeden ekran. Są ekrany logowania, listy, szczegółów, ustawień, a nawigacja to mechanizm przechodzenia między nimi. Poznasz dwa klasyczne sposoby: stos stron (NavigationPage) i okna modalne, oraz dwa sposoby przekazywania danych między stronami.
- około 55 minut
- .NET MAUI · NavigationPage · PushAsync · PushModalAsync
- INF.04.6.2
Po tej lekcji: przejść do nowej strony i wrócić (PushAsync/PopAsync), otworzyć okno modalne (PushModalAsync/PopModalAsync) oraz przekazać dane przez konstruktor i przez właściwość.
Dwa sposoby przejścia i powrotu z danymi
Wizytówka, szczegóły produktu czy formularz: aplikacje mają więcej niż jeden ekran. Zbudujesz stos stron i osobny ekran modalny, a imię przejdzie razem z nawigacją.
Najpierw uruchomisz mały ekran. Potem połączysz go z kodem i sprawdzisz konkretne wyniki. Dodatki wykonuj dopiero, gdy wersja podstawowa działa. Quiz i oceniane zadania pozostają w biurku po zalogowaniu.
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
1 · Sprawdź w działaniu
Zobacz, co dzieje się na stosie
Wpisz imię i kliknij PushAsync: na stosie pojawi się SecondPage, a w pasku strzałka wstecz. Otwórz okno modalne i zauważ, że nie ma przycisku wstecz. Odznacz opcję NavigationPage i spróbuj PushAsync, aby zobaczyć błąd.
Najpierw przewidź, potem sprawdź: Dodaj stronę na stos, potem wróć. Porównaj to z otwarciem modala. Odpowiedz, czy PopAsync i PopModalAsync zdejmują tę samą warstwę.
Push/Pop działają na stosie stron. Okno modalne jest osobnym stosem i wymaga jawnego zamknięcia. Model pomaga zobaczyć mechanizm; właściwą aplikację uruchomisz z plików poniżej.
1. Przygotuj miejsce pracy
Co dodajesz, a co podmieniasz?
Stronę dodaj przez Projekt → Dodaj → Nowy element → .NET MAUI ContentPage (XAML). Powstaje para .xaml i .xaml.cs. Dla ContentView wybierz szablon ContentView; dla modeli i serwisów zwykłą klasę. Jeśli plik już istnieje, podmień wskazaną zawartość — nie twórz drugiej klasy o tej samej nazwie.
| Plik | Rola w ćwiczeniu |
|---|---|
| App.xaml.cs | Logika i obsługa danych |
| MainPage.xaml.cs | Logika i obsługa danych |
| SecondPage.xaml.cs | Logika i obsługa danych |
| ThirdPage.xaml.cs | Logika i obsługa danych |
| MainPage.xaml | Wygląd strony lub kontrolki |
| SecondPage.xaml | Wygląd strony lub kontrolki |
| ThirdPage.xaml | Wygląd strony lub kontrolki |
Zanim uruchomisz: trzy połączenia
x:Class="MojaAplikacja.NazwaStrony" w XAML musi zgadzać się z namespace MojaAplikacja i nazwą klasy C#. InitializeComponent() tworzy kontrolki opisane w XAML.
x:Name="PoleImie" daje kodowi C# dostęp przez PoleImie.Text. Z kolei Clicked="Zapisz_Clicked" wskazuje metodę o tej nazwie w pliku .xaml.cs. Sam napis przycisku w Text niczego nie podpina.
Gdy dodajesz XAML z obsługą zdarzeń, od razu uzupełnij też odpowiadający C#. Uruchamiaj dopiero po skończeniu oznaczonej pary plików; brakujący handler nie jest błędem środowiska.
2. Uruchom sam wygląd — jeszcze bez logiki
W świeżym projekcie zastąp MainPage.xaml poniższym ekranem. W MainPage.xaml.cs zachowaj konstruktor z InitializeComponent(); usuń szablonowy licznik i OnCounterClicked, bo nie ma ich już w XAML. Na tym etapie App i AppShell pozostają z szablonu. To pełny, tymczasowy XAML — później świadomie go podmienisz, nie dokleisz do drugiego ContentPage.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MojaAplikacja.MainPage">
<VerticalStackLayout Padding="24" Spacing="14">
<Label Text="Pierwszy ekran" FontSize="24" />
<Entry Placeholder="Imię do przekazania" />
<Button Text="Drugi ekran — za chwilę" />
</VerticalStackLayout>
</ContentPage>
- Pierwsza próba Uruchom. Zobaczysz kontrolki, ale przyciski bez Clicked jeszcze nic nie robią. Sprawdź rozmiar i kolejność elementów. Zatrzymaj aplikację przed następnym etapem.
Zacznijmy od kontaktów
Stos kartek i okno na wierzchu
Przejście z listy produktów do szczegółów produktu i powrót to stos stron: PushAsync dokłada kartkę na wierzch, PopAsync ją zdejmuje. Formularz „Dodaj nowy kontakt”, który otwiera się na wierzchu listy i trzeba go świadomie zamknąć, to nawigacja modalna.
2 · Ściągawka
Push, Pop i modal
| Metoda | Działanie |
|---|---|
await Navigation.PushAsync(new DrugaStrona()) | Przechodzi do nowej strony: dokłada ją na stos. |
await Navigation.PopAsync() | Wraca do poprzedniej strony: zdejmuje bieżącą ze stosu. |
await Navigation.PopToRootAsync() | Zdejmuje wszystkie strony, zostaje główna. |
await Navigation.PushModalAsync(new Strona()) | Otwiera stronę jako modalne okno „na wierzchu”. |
await Navigation.PopModalAsync() | Zamyka okno modalne. |
4. Połącz wygląd z działaniem
Teraz zbuduj docelowy przykład. Pełne pliki poniżej zastępują swoje wcześniejsze wersje. Przeczytaj opis nad kodem i objaśnienia pod nim; potem sprawdź przepływ danych, nie tylko brak czerwonych podkreśleń.
Gdy przykład ma kilka plików zależnych od siebie, najpierw dodaj wszystkie wskazane typy, a potem uruchom całość. Ustaw breakpoint w obsłudze głównego przycisku i prześledź jedną próbę.
Budowa krok po kroku
App.xaml.cs: okno z NavigationPage
Po utworzeniu stron podmień App.xaml.cs. NavigationPage musi być korzeniem okna, żeby stosowe PushAsync i PopAsync miały właściwy kontekst.
Aby PushAsync i PopAsync działały, aplikacja musi zaczynać od NavigationPage.
namespace MojaAplikacja;
public partial class App : Application
{
public App()
{
InitializeComponent();
}
// Okno aplikacji zawiera NavigationPage, dzięki czemu działają PushAsync i PopAsync
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new NavigationPage(new MainPage()));
}
}
new Window(new NavigationPage(new MainPage()))Stos nawigacji startuje odMainPage. Strony pokazują pasek z tytułem i strzałką wstecz.CreateWindowW nowszych wersjach MAUI okno tworzysz w tej metodzie. W starszych materiałach zobaczyszMainPage = new NavigationPage(new MainPage());.
Budowa krok po kroku
Widok MainPage
Dodaj lub otwórz MainPage.xaml i podmień jego zawartość. Najpierw odszukaj kontener, potem nazwane kontrolki oraz wskazane zdarzenia. Pozostaw zgodne x:Class i nazwę klasy w pliku .xaml.cs.
Dodaj stronę szablonem ContentPage (XAML), a następnie dopasuj XAML i omówiony wyżej code-behind. Nie wystarczy utworzyć pustej klasy C#.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MojaAplikacja.MainPage">
<VerticalStackLayout Padding="20" Spacing="12">
<Entry x:Name="PoleImie" Placeholder="Imię" />
<Button Text="Druga strona" Clicked="OnGoClicked" />
<Button Text="Strona modalna" Clicked="OnModalClicked" />
</VerticalStackLayout>
</ContentPage>
- Przeczytaj powiązanie x:Name identyfikuje kontrolkę, a Binding odczytuje właściwość obiektu ustawionego jako BindingContext. To dwa różne mechanizmy.
Budowa krok po kroku
MainPage.xaml.cs
Odczytaj imię przed przejściem. SecondPage dostaje argument konstruktora; ThirdPage właściwość ustawioną przed PushModalAsync.
Dwa przyciski: zwykłe przejście z przekazaniem imienia oraz okno modalne.
namespace MojaAplikacja;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private async void OnGoClicked(object sender, EventArgs e)
{
string imie = PoleImie.Text ?? "";
// Przekazanie danych PRZEZ KONSTRUKTOR drugiej strony
await Navigation.PushAsync(new SecondPage(imie));
}
private async void OnModalClicked(object sender, EventArgs e)
{
var trzecia = new ThirdPage { Imie = PoleImie.Text ?? "" };
await Navigation.PushModalAsync(trzecia); // okno modalne: bez przycisku „wstecz”
}
}
PoleImie.Text ?? ""Zamienianullna pusty napis, aby nie przekazać pustego odwołania.new SecondPage(imie)Dane przekazane przez konstruktor nowej strony, w chwili jej tworzenia.PushModalAsync(trzecia)Otwiera stronę jako okno modalne.
Budowa krok po kroku
Widok SecondPage
Dodaj lub otwórz SecondPage.xaml i podmień jego zawartość. Najpierw odszukaj kontener, potem nazwane kontrolki oraz wskazane zdarzenia. Pozostaw zgodne x:Class i nazwę klasy w pliku .xaml.cs.
Dodaj stronę szablonem ContentPage (XAML), a następnie dopasuj XAML i omówiony wyżej code-behind. Nie wystarczy utworzyć pustej klasy C#.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MojaAplikacja.SecondPage">
<VerticalStackLayout Padding="20" Spacing="12">
<Label x:Name="LabelImie" />
<Button Text="Wróć" Clicked="OnBackClicked" />
</VerticalStackLayout>
</ContentPage>
- Przeczytaj powiązanie x:Name identyfikuje kontrolkę, a Binding odczytuje właściwość obiektu ustawionego jako BindingContext. To dwa różne mechanizmy.
Budowa krok po kroku
SecondPage.xaml.cs
Konstruktor nie jest tu bezargumentowy. new SecondPage(imie) musi przekazać wartość; po InitializeComponent ustawiamy etykietę.
Druga strona odbiera imię jako parametr konstruktora i od razu pokazuje powitanie. MAUI sam pamięta, skąd użytkownik przyszedł.
namespace MojaAplikacja;
public partial class SecondPage : ContentPage
{
public SecondPage(string imie)
{
InitializeComponent();
LabelImie.Text = $"Witaj, {imie}!";
}
private async void OnBackClicked(object sender, EventArgs e)
{
// Powrót do poprzedniej strony (zdejmuje SecondPage ze stosu)
await Navigation.PopAsync();
}
}
public SecondPage(string imie)Konstruktor z parametrem: dane dostajesz w chwili tworzenia strony.InitializeComponent()przed użyciem kontrolek Najpierw tworzymy kontrolki, dopiero potem ustawiamyLabelImie.Text.await Navigation.PopAsync()Zdejmuje stronę ze stosu i wraca do poprzedniej.
Budowa krok po kroku
Widok ThirdPage
Dodaj lub otwórz ThirdPage.xaml i podmień jego zawartość. Najpierw odszukaj kontener, potem nazwane kontrolki oraz wskazane zdarzenia. Pozostaw zgodne x:Class i nazwę klasy w pliku .xaml.cs.
Dodaj stronę szablonem ContentPage (XAML), a następnie dopasuj XAML i omówiony wyżej code-behind. Nie wystarczy utworzyć pustej klasy C#.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MojaAplikacja.ThirdPage">
<VerticalStackLayout Padding="20" Spacing="12">
<Label x:Name="EtykietaWiadomosc" />
<Button Text="Zamknij" Clicked="OnZamknijClicked" />
</VerticalStackLayout>
</ContentPage>
- Przeczytaj powiązanie x:Name identyfikuje kontrolkę, a Binding odczytuje właściwość obiektu ustawionego jako BindingContext. To dwa różne mechanizmy.
Budowa krok po kroku
ThirdPage.xaml.cs
Modal ma własny sposób zamknięcia PopModalAsync. Porównaj go z PopAsync na zwykłym stosie.
Dane można też przekazać przez właściwość: tworzysz stronę, ustawiasz właściwość i dopiero wtedy ją pokazujesz. Odczyt robisz w OnAppearing().
namespace MojaAplikacja;
public partial class ThirdPage : ContentPage
{
// Dane przekazane PRZEZ WŁAŚCIWOŚĆ: ustawiamy je PRZED PushAsync
public string Imie { get; set; } = "";
public ThirdPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
EtykietaWiadomosc.Text = $"Cześć, {Imie}!"; // odczyt po pojawieniu się strony
}
private async void OnZamknijClicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
public string Imie { get; set; }Publiczna właściwość, którą ustawi strona wywołująca.OnAppearing()Uruchamia się, gdy strona staje się widoczna, więc właściwość jest już ustawiona.await Navigation.PopModalAsync()Okno modalne zamykamy jawnie (nie ma przycisku wstecz).
5. Odbiór: czy naprawdę działa?
Wykonaj próby w swojej aplikacji, nie tylko w modelu na stronie. Zaznaczaj dopiero po sprawdzeniu wyniku. Funkcje urządzenia wymagają testu na właściwej platformie.
7 · Czego unikać
Cztery błędy w nawigacji
Brak `NavigationPage`
return new Window(new MainPage());Navigation.PushAsync zgłasza wyjątek, bo strona nie ma stosu nawigacji.
return new Window(new NavigationPage(new MainPage()));Stos stron istnieje tylko w NavigationPage.
Mylenie `PushAsync` z `PushModalAsync`
await Navigation.PushModalAsync(new SzczegolyPage()); // zwykłe szczegółyBrak przycisku „wstecz”, a użytkownik musi zamknąć okno jawnie.
await Navigation.PushAsync(new SzczegolyPage());Modal jest do formularzy i potwierdzeń, a zwykłe przejścia do PushAsync.
Właściwość ustawiona po pokazaniu strony
await Navigation.PushAsync(trzecia);
trzecia.Imie = "Ola";OnAppearing() wykonało się z pustym Imie.
trzecia.Imie = "Ola";
await Navigation.PushAsync(trzecia);Dane muszą być gotowe, zanim strona stanie się widoczna.
Brak `await` przed nawigacją
Navigation.PushAsync(new SecondPage(imie));Kod idzie dalej, nie czekając na przejście. Możliwe nieprzewidywalne zachowanie animacji.
await Navigation.PushAsync(new SecondPage(imie));Metody nawigacji są asynchroniczne.
Ćwiczenie z pomocą · samodzielna praca
6. Mała zmiana, którą zrobisz samodzielnie
Przekaż do SecondPage także nazwę klasy ucznia.
Przekaż do SecondPage także nazwę klasy ucznia. Dotychczasowe działanie ma pozostać poprawne.
? Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź
Dodaj drugi Entry na MainPage.
Krok 2 — pokaż podpowiedź
Rozszerz konstruktor SecondPage o drugi argument typu string.
Krok 3 — pokaż podpowiedź
Uzupełnij zarówno wywołanie new SecondPage(...), jak i tekst wyświetlany w konstruktorze.
Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.
8 · Sprawdź się
Którą metodę nawigacji?
Cztery sytuacje.
Podsumowanie
Co warto zapamiętać
NavigationPagetworzy stos stron:PushAsyncdokłada,PopAsynczdejmuje,PopToRootAsyncwraca do głównej.- Okno modalne:
PushModalAsynciPopModalAsync, bez przycisku wstecz. - Dane przekaż przez konstruktor albo przez **właściwość ustawioną przed
PushAsync** (odczyt wOnAppearing()). - Metody nawigacji są asynchroniczne: używaj
awaitw metodzieasync. - Bez
NavigationPagewCreateWindowmetodyPush/Popzgłoszą wyjątek.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →