Dataniedziela, 9 sierpnia 2026 Czas07:36:12
← Aplikacje mobilne (.NET MAUI)

Lekcja 9. Obsługa zdarzeń — anatomia handlera i okna DisplayAlert

Średni

Po co się tego uczymy?

W aplikacji mobilnej mamy dwie części: XAML (wygląd) i C# (logika). Żeby aplikacja zareagowała na kliknięcie czy wpisanie tekstu, trzeba połączyć kontrolkę z metodą w C# — to złączenie zdarzenia z metodą. Ta lekcja rozkłada na czynniki pierwsze anatomię takiej metody i pokazuje dwa najważniejsze okna dialogowe: DisplayAlert i DisplayPromptAsync.

Teoria

Czym jest złączenie zdarzenia?

W XAML: <Button Text="Kliknij mnie" Clicked="PrzyciskKlik_Click"/>. W C#: metoda o dokładnie tej samej nazwie, wykonywana po kliknięciu. Złączenie = wskazanie, że dana kontrolka ma uruchomić konkretną metodę, gdy wydarzy się określone zdarzenie (np. Clicked).

Anatomia metody obsługującej zdarzenie

Weźmy przykład: private async void Zaloguj_Click(object sender, EventArgs e). Rozbijmy to na części:

Element Znaczenie
private Metoda widoczna tylko w tej klasie — wystarcza w naszych projektach.
async Pozwala użyć await — np. czekać na wyświetlenie okna dialogowego. Dzięki temu aplikacja się NIE zawiesza.
void Metoda nic nie zwraca — handlery zdarzeń prawie zawsze są void.
Zaloguj_Click Nazwa metody — konwencja: nazwa kontrolki + rodzaj zdarzenia (np. Przycisk_Click, Suwak_ValueChanged).
object sender Obiekt, który wywołał zdarzenie — np. konkretny przycisk, który kliknięto.
EventArgs e Dodatkowe dane o zdarzeniu — dla różnych kontrolek różne typy (np. ValueChangedEventArgs dla suwaka, DateChangedEventArgs dla DatePickera).

DisplayAlert — komunikat dla użytkownika

await DisplayAlert("Tytuł", "Treść", "OK") pokazuje proste okno z komunikatem i jednym przyciskiem. Wersja z DWOMA przyciskami (DisplayAlert("Tytuł", "Treść", "Tak", "Nie")) zwraca booltrue, gdy kliknięto pierwszy przycisk ("Tak"), false, gdy drugi ("Nie"). To najczęstszy sposób pytania użytkownika o potwierdzenie ważnej akcji (np. usunięcia danych).

DisplayPromptAsync — szybkie okno wprowadzania danych

string wynik = await DisplayPromptAsync("Tytuł", "Treść pytania") to odpowiednik klasycznego "InputBox" — otwiera okno z polem tekstowym i zwraca wpisany string (albo null, gdy użytkownik anuluje).

Dlaczego async/await w interfejsie użytkownika?

Operacje takie jak DisplayAlert czy DisplayPromptAsync są asynchroniczne — nie blokują wątku odpowiedzialnego za rysowanie interfejsu. Dzięki async/await aplikacja pozostaje płynna, a użytkownik widzi okno dialogowe natychmiast, zamiast czekać na "zamrożoną" aplikację.

Dobra praktyka: opakowuj kod w handlerze w try/catch, żeby ewentualny błąd pokazał krótki komunikat zamiast wywalić całą aplikację:

private async void Handler(object sender, EventArgs e)
{
    try
    {
        await DisplayAlert("Tytuł", "Treść", "OK");
    }
    catch (Exception ex)
    {
        await DisplayAlert("Błąd", ex.Message, "OK");
    }
}

Kiedy sender, a kiedy x:Name?

Masz jedną kontrolkę i używasz jej często → nadaj jej x:Name i odwołuj się po nazwie (prościej, czytelniej). Jeden wspólny handler dla WIELU kontrolek → czytaj sender i rzutuj do właściwego typu: if (sender is Button b) b.Text = "OK";

Schemat

Anatomia metody obslugujacej zdarzenie:

private   async   void   Zaloguj_Click (object sender, EventArgs e)
  |         |       |          |              |            |
dostep   pozwala  nic nie   nazwa:        kto wywolal   dane o
tylko    uzyc     zwraca    kontrolka_    zdarzenie     zdarzeniu
w klasie await              Zdarzenie     (np. Button)

Przykład z życia

Kliknięcie "Usuń konto" w dowolnej aplikacji ZAWSZE pokazuje okno potwierdzenia ("Czy na pewno chcesz usunąć konto? Tak/Nie") — to dokładnie DisplayAlert z dwoma przyciskami. Gdyby aplikacja usuwała dane od razu po jednym kliknięciu, bez potwierdzenia, byłby to poważny błąd projektowy UX.

PotwierdzeniePage.xaml

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ZdarzeniaApp.PotwierdzeniePage"
             Title="Potwierdzenie">

    <VerticalStackLayout Padding="20" Spacing="12">
        <Label Text="Potwierdzenie usunięcia" FontSize="20" />

        <Button Text="Usuń element" Clicked="Usun_Click" />

        <Button Text="Podaj swoje imię" Clicked="PodajImie_Click" />

        <Label x:Name="StatusLabel" FontSize="16" />
    </VerticalStackLayout>
</ContentPage>

PotwierdzeniePage.xaml.cs

namespace ZdarzeniaApp;

public partial class PotwierdzeniePage : ContentPage
{
    public PotwierdzeniePage() => InitializeComponent();

    private async void Usun_Click(object sender, EventArgs e)
    {
        // DisplayAlert z dwoma przyciskami zwraca bool:
        // true = kliknieto pierwszy ("Tak"), false = drugi ("Nie")
        bool decyzja = await DisplayAlert(
            "Usuwanie", "Czy na pewno chcesz usunąć?", "Tak", "Nie");

        StatusLabel.Text = decyzja ? "Usunięto." : "Anulowano.";
    }

    private async void PodajImie_Click(object sender, EventArgs e)
    {
        // DisplayPromptAsync to szybkie okno wprowadzania tekstu
        string imie = await DisplayPromptAsync("Wpisz imię", "Podaj swoje imię:");

        if (!string.IsNullOrWhiteSpace(imie))
            StatusLabel.Text = $"Witaj, {imie}!";
    }
}

Komentarz i wyjaśnienie kodu

Usun_Click pokazuje wzorzec potwierdzenia akcji: DisplayAlert z dwoma przyciskami ("Tak"/"Nie") zwraca bool, który wykorzystujemy w operatorze warunkowym ?:, żeby ustawić odpowiedni komunikat w StatusLabel bez pisania pełnego if/else.

PodajImie_Click pokazuje DisplayPromptAsync — zwraca wpisany tekst jako string. Sprawdzamy !string.IsNullOrWhiteSpace(imie), żeby nie wypisać pustego powitania, gdy użytkownik kliknie "Anuluj" (wtedy metoda zwraca null) albo nic nie wpisze.

Obie metody są oznaczone async void — bo obie korzystają z await przy wywołaniu okna dialogowego.

Ćwiczenie samodzielne

Utwórz stronę z powyższym kodem. Sprawdź działanie obu przycisków — kliknij "Tak" i "Nie" w oknie potwierdzenia, a potem wpisz imię (i osobno spróbuj kliknąć "Anuluj") w oknie DisplayPromptAsync.

Zadania do pracy własnej

  1. Zmień tekst pytania w DisplayAlert na własny (np. dotyczący usunięcia zdjęcia zamiast 'elementu').

  2. Dodaj trzeci przycisk 'Wyloguj', który pokazuje DisplayAlert z komunikatem 'Zostałeś wylogowany' i JEDNYM przyciskiem 'OK' (bez pytania o potwierdzenie).

  3. Zbuduj mini-quiz: przycisk 'Zadaj pytanie' pokazuje DisplayPromptAsync z pytaniem matematycznym (np. 'Ile to 7 razy 8?'), a po otrzymaniu odpowiedzi (przez int.TryParse) sprawdza, czy jest poprawna, i pokazuje DisplayAlert z komunikatem 'Brawo!' albo 'Niestety, spróbuj ponownie' — wszystko opakowane w try/catch na wypadek niepoprawnego formatu odpowiedzi.

Typowe błędy

Brak async przy używaniu await — jeśli metoda korzysta z await, musi być oznaczona async, inaczej kod się nie skompiluje.

Brak sprawdzenia null po DisplayPromptAsync — gdy użytkownik kliknie "Anuluj", metoda zwraca null; użycie tego wyniku bez sprawdzenia (np. wywołanie na nim metody) rzuci wyjątek.

Niezgodność nazwy metody w XAML i code-behind — literówka w Clicked="Usun_Click" względem faktycznej nazwy metody w C# uniemożliwi kompilację.

Blokujące operacje bez await — próba wykonania czegoś czasochłonnego bez async/await zamrozi interfejs użytkownika na czas trwania operacji.

Nawiązanie do egzaminu zawodowego

To realizacja INF.04.6.2 w zakresie łączenia interfejsu z logiką aplikacji. Umiejętność poprawnego napisania handlera zdarzenia (sygnatura, async/await, obsługa DisplayAlert) jest sprawdzana niemal w każdym zadaniu praktycznym z aplikacją mobilną na egzaminie.