Wstęp – co to są złączenia i po co one są?
W aplikacji mobilnej w .NET MAUI mamy dwie części:
- XAML – opis wyglądu strony (jak HTML w stronach internetowych),
- C# – logika, czyli co się ma stać po kliknięciu, wpisaniu tekstu itp.
Aby aplikacja zareagowała na akcję użytkownika (np. kliknięcie przycisku), trzeba połączyć kontrolkę z metodą w C#. Takie połączenie nazywamy złączeniem zdarzenia z metodą.
W praktyce wygląda to tak:
W XAML:
<Button Text="Kliknij mnie" Clicked="PrzyciskKlik_Click"/>
W C#:
private void PrzyciskKlik_Click(object sender, EventArgs e)
{
// kod, który wykona się po kliknięciu
}
Czyli: złączenie = wskazanie, że dana kontrolka ma uruchomić konkretną metodę, gdy wydarzy się jakieś zdarzenie (np. Clicked).
Z czego składa się metoda obsługująca zdarzenie?
Każda taka metoda ma swoją „anatomie” – elementy, które zawsze się pojawiają.
Przykład:
private async void Zaloguj_Click(object sender, EventArgs e)
{
await DisplayAlert("Logowanie", "Kliknięto przycisk Zaloguj.", "OK");
}
Rozbijmy to na kawałki:
private– metoda jest widoczna tylko w tej klasie. To wystarcza w naszych projektach.async– oznacza, że metoda może korzystać zawait, czyli np. czekać na wyświetlenie okna (DisplayAlert,DisplayPromptAsync). Dzięki temu aplikacja się nie zawiesza.void– metoda nic nie zwraca. Handlery zdarzeń (czyli metody reagujące na akcje) prawie zawsze sąvoid.Zaloguj_Click– nazwa metody. Zwykle tworzymy ją tak: nazwa kontrolki + rodzaj zdarzenia (np.Przycisk_Click,Suwak_ValueChanged).object sender– to obiekt, który wywołał zdarzenie. Jeśli klikniemy przycisk, to wsendersiedzi właśnie ten przycisk.EventArgs e– dodatkowe dane o zdarzeniu.- Przy prostym kliknięciu to „puste” dane (
EventArgs). - Przy suwaku (
Slider) mamyValueChangedEventArgsz nową wartością. - Przy wyborze daty (
DatePicker) dostajemyDateChangedEventArgsz nową i starą datą.
- Przy prostym kliknięciu to „puste” dane (
1) Komunikat – DisplayAlert
XAML
<?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="PrzewodnikZoo.Page03_Alert"
Title="Alert">
<VerticalStackLayout Padding="20" Spacing="12">
<!-- Nagłówek sekcji -->
<Label Text="Wyświetl informację" FontSize="20"/>
<!-- Po kliknięciu wywoła metodę Info_Click w C# -->
<Button Text="Pokaż Alert" Clicked="Info_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page03_Alert : ContentPage
{
public Page03_Alert() => InitializeComponent(); // łączy XAML z C#
// Metoda zdarzeniowa – uruchamia się po kliknięciu przycisku.
// 'async' pozwala użyć await; 'void' jest typowe dla handlerów zdarzeń.
private async void Info_Click(object sender, EventArgs e)
{
try
{
// DisplayAlert: (tytuł, treść, tekst przycisku)
await DisplayAlert("Informacja", "To jest przykładowy komunikat.", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Błąd", ex.Message, "OK");
}
}
}
Co tu się dzieje:
- Gdy użytkownik kliknie przycisk, MAUI wywołuje metodę zdarzeniową
Info_Click. async/await– boDisplayAlertjest operacją asynchroniczną (okno dialogowe).InitializeComponent()– tworzy kontrolki z XAML i wiąże je z klasą.- Try/catch zabezpiecza aplikację, żeby nie wysypała się w razie błęd
2) Potwierdzenie akcji (Tak/Nie)
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page04_Potwierdzenie" Title="Potwierdzenie">
<VerticalStackLayout Padding="20" Spacing="12">
<Label Text="Potwierdzenie usunięcia" FontSize="20"/>
<!-- Po kliknięciu zapyta użytkownika o decyzję -->
<Button Text="Usuń element" Clicked="Usun_Click"/>
<!-- Tutaj pokażemy wynik decyzji -->
<Label x:Name="StatusLabel" FontSize="16"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page04_Potwierdzenie : ContentPage
{
public Page04_Potwierdzenie() => InitializeComponent();
private async void Usun_Click(object sender, EventArgs e)
{
// DisplayAlert zwraca bool: True gdy kliknięto pierwszy przycisk ("Tak"), False gdy drugi ("Nie").
bool decyzja = await DisplayAlert("Usuwanie", "Czy na pewno chcesz usunąć?", "Tak", "Nie");
StatusLabel.Text = decyzja ? "Usunięto." : "Anulowano.";
}
}
Co tu się dzieje:
DisplayAlertz dwoma przyciskami zwraca bool.- Używamy operatora warunkowego
?:do ustawienia wyniku wStatusLabel.
3) Okno wprowadzania danych – DisplayPromptAsync
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page03a_Prompt" Title="Prompt">
<VerticalStackLayout Padding="20" Spacing="12">
<Button Text="Podaj imię" Clicked="PodajImie_Click"/>
<Label x:Name="WynikLabel" />
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page03a_Prompt : ContentPage
{
public Page03a_Prompt() => InitializeComponent();
private async void PodajImie_Click(object sender, EventArgs e)
{
// Wyświetla okno z polem do wpisania tekstu i zwraca string (lub null, gdy anulujesz).
string imie = await DisplayPromptAsync("Wpisz imię", "Podaj swoje imię:");
if (!string.IsNullOrWhiteSpace(imie))
WynikLabel.Text = $"Witaj, {imie}!";
}
}
Co tu się dzieje:
DisplayPromptAsyncto szybkie InputBox.- Zwraca tekst, który od razu pokazujemy w
Label.
4) Odczyt z Entry
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page05_EntryOdczyt" Title="Entry">
<VerticalStackLayout Padding="20" Spacing="12">
<Entry x:Name="PoleTekstowe" Placeholder="Wpisz coś..."/>
<Button Text="Pokaż" Clicked="PokazTekst_Click"/>
<Label x:Name="WynikLabel" FontSize="18"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page05_EntryOdczyt : ContentPage
{
public Page05_EntryOdczyt() => InitializeComponent();
private void PokazTekst_Click(object sender, EventArgs e)
{
// Czytamy wartość z Entry przez jego właściwość Text.
WynikLabel.Text = $"Wpisałeś: {PoleTekstowe.Text}";
}
}
Co tu się dzieje:
x:Name="PoleTekstowe"pozwala odwołać się w C# do tej kontrolki.- Klik przycisku = odczyt
Texti wyświetlenie wLabel.
5) Zmiana tła strony
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page06_Tlo" Title="Tło">
<VerticalStackLayout Padding="20" Spacing="12">
<Label Text="Zmienianie koloru tła" FontSize="20"/>
<Button Text="Ustaw zielone tło" Clicked="ZmienTlo_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page06_Tlo : ContentPage
{
public Page06_Tlo() => InitializeComponent();
private void ZmienTlo_Click(object sender, EventArgs e)
{
// BackgroundColor należy do ContentPage – zmienia cały ekran.
BackgroundColor = Colors.LightGreen;
}
}
Co tu się dzieje:
- Modyfikujemy właściwość strony (
ContentPage) – zmiana dotyczy całego widoku.
6) Podmiana obrazka po kliknięciu
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page07_ZmienObraz" Title="Obraz">
<VerticalStackLayout Padding="20" Spacing="12">
<!-- Obraz startowy -->
<Image x:Name="Obrazek" Source="sowa.png" HeightRequest="180"/>
<Button Text="Zmień na słonia" Clicked="ZmienObraz_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page07_ZmienObraz : ContentPage
{
public Page07_ZmienObraz() => InitializeComponent();
private void ZmienObraz_Click(object sender, EventArgs e)
{
// Pliki obrazów trzymaj w Resources/Images i ustaw akcję kompilacji na MauiImage
// Wtedy możesz się odwoływać tylko nazwą pliku:
Obrazek.Source = "slon.png";
}
}
Co tu się dzieje:
Image.Sourcemoże wskazywać plik zResources/Imageslub ścieżkę lokalną/URL.
7) Zmiana tekstu w Label
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page09_LabelTekst" Title="Label">
<VerticalStackLayout Padding="20" Spacing="12">
<Label x:Name="MojaEtykieta" Text="Tekst początkowy" FontSize="20"/>
<Button Text="Zmień tekst" Clicked="ZmienTekst_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page09_LabelTekst : ContentPage
{
public Page09_LabelTekst() => InitializeComponent();
private void ZmienTekst_Click(object sender, EventArgs e)
{
// Podstawowa manipulacja właściwością Text
MojaEtykieta.Text = "Nowy tekst ustawiony w kodzie!";
}
}
Co tu się dzieje:
- Klasyczny handler zdarzenia → modyfikuje właściwość kontrolki.
8) Switch – tryb nocny
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page10_SwitchTryb" Title="Switch">
<VerticalStackLayout Padding="20" Spacing="12">
<Label Text="Tryb nocny" FontSize="20"/>
<!-- Zdarzenie Toggled wyśle e.Value: True / False -->
<Switch Toggled="TrybNocny_Toggled"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page10_SwitchTryb : ContentPage
{
public Page10_SwitchTryb() => InitializeComponent();
private void TrybNocny_Toggled(object sender, ToggledEventArgs e)
{
// e.Value to aktualny stan przełącznika
BackgroundColor = e.Value ? Colors.Black : Colors.White;
}
}
Co tu się dzieje:
ToggledEventArgsprzekazuje nowy stan przełącznika (e.Value).
9) Slider – odczyt wartości
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page11_Slider" Title="Slider">
<VerticalStackLayout Padding="20" Spacing="12">
<Label x:Name="JasnoscLabel" Text="Jasność: 50%" FontSize="20"/>
<!-- ValueChanged daje nam starą i nową wartość -->
<Slider Minimum="0" Maximum="100" Value="50" ValueChanged="JasnoscSlider_ValueChanged"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page11_Slider : ContentPage
{
public Page11_Slider() => InitializeComponent();
private void JasnoscSlider_ValueChanged(object sender, ValueChangedEventArgs e)
{
// e.NewValue to nowa wartość suwaka (double)
JasnoscLabel.Text = $"Jasność: {e.NewValue:F0}%";
}
}
Co tu się dzieje:
- Format
{F0}– zaokrąglenie do 0 miejsc po przecinku (ładniejszy zapis).
10) Stepper – licznik
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page12_Stepper" Title="Stepper">
<VerticalStackLayout Padding="20" Spacing="12">
<Label x:Name="LicznikLabel" Text="Wartość: 0" FontSize="20"/>
<Stepper Minimum="0" Maximum="10" Increment="1" ValueChanged="LicznikStepper_ValueChanged"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page12_Stepper : ContentPage
{
public Page12_Stepper() => InitializeComponent();
private void LicznikStepper_ValueChanged(object sender, ValueChangedEventArgs e)
{
LicznikLabel.Text = $"Wartość: {e.NewValue}";
}
}
Co tu się dzieje:
Stepperzmienia wartość skokowo – kontrolujesz toIncrement.
11) DatePicker – wybór daty
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page13_DatePicker" Title="DatePicker">
<VerticalStackLayout Padding="20" Spacing="12">
<!-- DateSelected odpala się po zmianie daty -->
<DatePicker DateSelected="DataWybor_DateSelected"/>
<Label x:Name="WynikLabel" FontSize="18"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page13_DatePicker : ContentPage
{
public Page13_DatePicker() => InitializeComponent();
private void DataWybor_DateSelected(object sender, DateChangedEventArgs e)
{
// e.NewDate – nowo wybrana data (DateTime)
WynikLabel.Text = $"Wybrana data: {e.NewDate:d}";
}
}
Co tu się dzieje:
- Ładny skrót formatu
:d– data w krótkim formacie lokalnym.
12) TimePicker – wybór czasu
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page14_TimePicker" Title="TimePicker">
<VerticalStackLayout Padding="20" Spacing="12">
<!-- Słuchamy PropertyChanged, bo TimePicker nie ma osobnego eventu -->
<TimePicker x:Name="GodzinaWybor" PropertyChanged="GodzinaWybor_PropertyChanged"/>
<Label x:Name="WynikLabel" FontSize="18"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page14_TimePicker : ContentPage
{
public Page14_TimePicker() => InitializeComponent();
private void GodzinaWybor_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// Reagujemy tylko, gdy zmieniła się właściwość 'Time'
if (e.PropertyName == nameof(TimePicker.Time))
WynikLabel.Text = $"Wybrana godzina: {GodzinaWybor.Time}";
}
}
Co tu się dzieje:
PropertyChangedobsługuje zmiany różnych właściwości – filtrujemy po nazwie.
13) Picker – lista wyboru
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page15_PickerLista" Title="Picker">
<VerticalStackLayout Padding="20" Spacing="12">
<Picker x:Name="GatunkiPicker" Title="Wybierz gatunek"
SelectedIndexChanged="Picker_SelectedIndexChanged">
<!-- Wbudowane źródło danych (na szybko) -->
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Słoń</x:String>
<x:String>Sowa</x:String>
<x:String>Pingwin</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Label x:Name="WynikLabel" FontSize="18"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page15_PickerLista : ContentPage
{
public Page15_PickerLista() => InitializeComponent();
private void Picker_SelectedIndexChanged(object sender, EventArgs e)
{
// SelectedItem – bezpieczny rzut do string
if (GatunkiPicker.SelectedItem is string nazwa)
WynikLabel.Text = $"Wybrano: {nazwa}";
}
}
Co tu się dzieje:
- Na egzaminie często zmieniasz
Labelpo wyborze pozycji zPicker.
14) CheckBox – wybór wielu opcji
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page16_CheckBox" Title="CheckBox">
<VerticalStackLayout Padding="20" Spacing="12">
<CheckBox x:Name="Opcja1"/>
<Label Text="Akceptuję regulamin" />
<Button Text="Sprawdź" Clicked="Sprawdz_Click"/>
<Label x:Name="StatusLabel"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page16_CheckBox : ContentPage
{
public Page16_CheckBox() => InitializeComponent();
private void Sprawdz_Click(object sender, EventArgs e)
{
// IsChecked – True gdy zaznaczony
StatusLabel.Text = Opcja1.IsChecked ? "Regulamin zaakceptowany" : "Musisz zaakceptować!";
}
}
Co tu się dzieje:
CheckBoxprzechowuje stan logiczny wIsChecked.
15) RadioButton – jedna opcja z wielu
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page17_Radio" Title="RadioButton">
<VerticalStackLayout Padding="20" Spacing="8">
<!-- Ta sama grupa = tylko jedna opcja zaznaczona -->
<RadioButton x:Name="OpcjaA" Content="Opcja A" GroupName="Grupa"/>
<RadioButton x:Name="OpcjaB" Content="Opcja B" GroupName="Grupa"/>
<RadioButton x:Name="OpcjaC" Content="Opcja C" GroupName="Grupa"/>
<Button Text="Sprawdź" Clicked="SprawdzWybor_Click"/>
<Label x:Name="WynikLabel"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page17_Radio : ContentPage
{
public Page17_Radio() => InitializeComponent();
private void SprawdzWybor_Click(object sender, EventArgs e)
{
if (OpcjaA.IsChecked) WynikLabel.Text = "Wybrano A";
else if (OpcjaB.IsChecked) WynikLabel.Text = "Wybrano B";
else if (OpcjaC.IsChecked) WynikLabel.Text = "Wybrano C";
else WynikLabel.Text = "Nie wybrano niczego";
}
}
Co tu się dzieje:
GroupNamełączy przyciski w jedną grupę – jedna opcja aktywna.
16) SearchBar – wyszukiwanie
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page18_Search" Title="SearchBar">
<VerticalStackLayout Padding="20" Spacing="12">
<!-- Enter / ikona lupy wywołuje SearchButtonPressed -->
<SearchBar x:Name="Szukaj" Placeholder="Szukaj..." SearchButtonPressed="SearchBar_SearchButtonPressed"/>
<Label x:Name="WynikLabel"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page18_Search : ContentPage
{
public Page18_Search() => InitializeComponent();
private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
{
var sb = (SearchBar)sender; // 'sender' to kontrolka, która wywołała zdarzenie
WynikLabel.Text = $"Wyszukano: {sb.Text}";
}
}
Co tu się dzieje:
senderczęsto rzutujemy na właściwy typ kontrolki, by czytać jej właściwości.
17) ProgressBar – pasek postępu
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page19_Progress" Title="ProgressBar">
<VerticalStackLayout Padding="20" Spacing="12">
<ProgressBar x:Name="PostepBar" Progress="0.3"/>
<Button Text="Dodaj 20%" Clicked="DodajPostep_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page19_Progress : ContentPage
{
public Page19_Progress() => InitializeComponent();
private void DodajPostep_Click(object sender, EventArgs e)
{
// Progress: 0.0 – 1.0
PostepBar.Progress = Math.Min(1.0, PostepBar.Progress + 0.2);
}
}
Co tu się dzieje:
- Zabezpieczamy się przed przekroczeniem 1.0 (
Math.Min).
18) ActivityIndicator – animacja ładowania
XAML
<ContentPage ... x:Class="PrzewodnikZoo.Page20_Loader" Title="Ładowanie">
<VerticalStackLayout Padding="20" Spacing="12">
<ActivityIndicator x:Name="Loader" IsRunning="False" Color="Red"/>
<HorizontalStackLayout Spacing="10">
<Button Text="Start" Clicked="Start_Click"/>
<Button Text="Stop" Clicked="Stop_Click"/>
</HorizontalStackLayout>
</VerticalStackLayout>
</ContentPage>
C#
namespace PrzewodnikZoo;
public partial class Page20_Loader : ContentPage
{
public Page20_Loader() => InitializeComponent();
private void Start_Click(object sender, EventArgs e) => Loader.IsRunning = true;
private void Stop_Click(object sender, EventArgs e) => Loader.IsRunning = false;
}
Co tu się dzieje:
IsRunningsteruje animacją „kółeczka”.
19) Wybór pliku – FilePicker (obraz do podglądu)
XAML
<ContentPage ... x:Class="PrzewodnikZoo.FormularzObraz" Title="Formularz z obrazem">
<VerticalStackLayout Padding="16" Spacing="12">
<Label Text="Tytuł:" FontAttributes="Bold"/>
<Entry x:Name="PoleTytul" Placeholder="Wpisz tytuł..." />
<Label Text="Opis:" FontAttributes="Bold"/>
<Editor x:Name="PoleOpis" Placeholder="Wpisz opis..." AutoSize="TextChanges" />
<Label Text="Obraz:" FontAttributes="Bold"/>
<Image x:Name="PodgladObraz" HeightRequest="200" Aspect="AspectFit" />
<Button Text="Wybierz obraz" Clicked="WybierzObraz_Click"/>
</VerticalStackLayout>
</ContentPage>
C#
using Microsoft.Maui.Storage; // FilePicker
namespace PrzewodnikZoo;
public partial class FormularzObraz : ContentPage
{
public FormularzObraz() => InitializeComponent();
private async void WybierzObraz_Click(object sender, EventArgs e)
{
// Okno systemowe wyboru pliku graficznego
var wynik = await FilePicker.PickAsync(new PickOptions
{
PickerTitle = "Wybierz obraz",
FileTypes = FilePickerFileType.Images
});
if (wynik != null)
{
// Ustawiamy obraz jako podgląd
PodgladObraz.Source = wynik.FullPath;
}
}
}
Co tu się dzieje:
FilePicker.PickAsyncotwiera natywne okno wyboru pliku i zwraca ścieżkę.- Przypisujemy ścieżkę do
Image.Source.
20) Nawigacja między stronami – Shell (bonus, często przydatne)
Rejestracja trasy (AppShell.xaml.cs)
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
// Rejestrujemy stronę, aby można było nawigować po nazwie
Routing.RegisterRoute(nameof(DrugaStrona), typeof(DrugaStrona));
}
}
XAML (przycisk przejścia)
<Button Text="Przejdź do strony 2" Clicked="Idz_Click"/>
C# (nawigacja)
private async void Idz_Click(object sender, EventArgs e)
{
// Nawigacja do zarejestrowanej strony
await Shell.Current.GoToAsync(nameof(DrugaStrona));
}
Co tu się dzieje:
- Shell upraszcza nawigację – rejestrowanie trasy +
GoToAsync. - Na INF.04 często wystarczy 1–2 ekrany – taki schemat jest idealny.
Szybkie wyjaśnienie elementów metody zdarzeniowej
private– dostęp tylko w tej klasie.async– pozwala użyćawait(operacje asynchroniczne: okna dialogowe, I/O).void– metody zdarzeniowe zwykle nic nie zwracają.Info_Click(object sender, EventArgs e)– standardowa sygnatura zdarzenia:sender→ kontrolka, która wywołała zdarzenie (możesz ją zrzutować, np.(Button)sender),e→ dane o zdarzeniu (dla różnych kontrolek różne typy, np.ToggledEventArgs,ValueChangedEventArgs).
***
Kiedy użyć sender, a kiedy x:Name?
- Masz jedną kontrolkę i używasz jej często → daj
x:Namei odwołuj się po nazwie (prościej, czytelniej). - Jeden handler dla wielu kontrolek → czytaj
senderi rzutuj do właściwego typu:private void Wspolny_Click(object sender, EventArgs e) { if (sender is Button b) b.Text = "OK"; }
Dlaczego async/await w UI?
- Nie blokujesz wątku UI (apka nie „zamarza”), a użytkownik widzi dialogi od razu.
- W handlerach trzymaj prostą zasadę:
private async void Handler(object s, EventArgs e) { try { await DisplayAlert("Tytuł", "Treść", "OK"); } catch (Exception ex) { // awaryjna informacja (na egzaminie: krótki komunikat) await DisplayAlert("Błąd", ex.Message, "OK"); } }
nameof – drobny, ale ważny nawyk
Używaj nameof(Właściwość) zamiast „magicznego stringa” – kompilator sprawdza pisownię:
if (e.PropertyName == nameof(TimePicker.Time))
{
WynikLabel.Text = $"Wybrana godzina: {GodzinaWybor.Time}";
}
Minimalny „wzorzec egzaminacyjny” (do szybkiego startu)
XAML:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AplikacjaEgzaminowa.LogowaniePage"
Title="Logowanie">
<VerticalStackLayout Padding="20" Spacing="12">
<Entry x:Name="PoleLogin" Placeholder="Login"/>
<Entry x:Name="PoleHaslo" Placeholder="Hasło" IsPassword="True"/>
<Button Text="Zaloguj" Clicked="Zaloguj_Click"/>
<Label x:Name="StatusLabel"/>
</VerticalStackLayout>
</ContentPage>
C#:
public partial class LogowaniePage : ContentPage
{
public LogowaniePage() => InitializeComponent();
private async void Zaloguj_Click(object sender, EventArgs e)
{
string login = PoleLogin.Text?.Trim();
string haslo = PoleHaslo.Text;
if (string.IsNullOrWhiteSpace(login) || string.IsNullOrWhiteSpace(haslo))
{
await DisplayAlert("Błąd", "Uzupełnij login i hasło.", "OK");
return;
}
// prosta „logika”
bool ok = (login == "admin" && haslo == "1234");
StatusLabel.Text = ok ? "Zalogowano" : "Nieprawidłowe dane";
}
}
Ten przykład pokazuje wszystko, co egzaminator chce zobaczyć: nazwane kontrolki, odczyt wartości, handler, async/await, komunikat, prostą walidację i zmianę właściwości w reakcji na zdarzenie.

