DATA
CZAS
IMIENINY
FAZA KSIĘŻYCA
STAFLOTA ⊕ SEKTOR ALFA · BITEDU STATION
INF.04 · .NET MAUI · przed egzaminem

Zbuduj dowolna aplikacje MAUI
w jednym schemacie

Ten artykul to sciagazka na dzien przed egzaminem. Jeden schemat dziala w kazdym zadaniu INF.04. Znajdziesz tu gotowe fragmenty kodu, tabele kontrolek, dwie kompletne aplikacje i checkjiste przed oddaniem.

Visual Studio 2022| .NET MAUI App| C# + XAML| Android Emulator / Windows
Podstawa

Kazda aplikacja MAUI = te same 3 warstwy

Zanim zaczniesz pisac kod – zapamietaj ten schemat. Egzaminator sprawdza czy go stosujesz.

01 / Widok

MainPage.xaml

Layout + kontrolki. Tu NIE ma zadnej logiki obliczeniowej. Tylko uklad ekranu.

02 / Polaczenie

MainPage.xaml.cs

Obsluga zdarzen (Clicked, TextChanged). Pobiera dane z kontrolek, wywoluje metode z klasy Logika, pokazuje wynik.

03 / Logika

Logika/Kalkulator.cs

Czysta klasa C# z metodami obliczeniowymi. Nie wie nic o przyciskach ani polach. Mozna ja testowac MSTest.

Zlota zasada INF.04: metoda obliczeniowa nigdy nie siedzi w obsludze przycisku. Code-behind tylko pobiera dane i pokazuje wynik. Obliczenia = osobna klasa.
Krok 1

Utworz projekt i uruchom aplikacje

1
Visual Studio 2022 -> Utworz nowy projekt

Wyszukaj .NET MAUI App (nie Blazor, nie Xamarin). Wybierz i kliknij Dalej.

2
Nazwij projekt bez spacji i polskich znakow

Np. RejestracjaApp, ListaSortowaniaApp. Spacje w nazwie = bledy przy kompilacji.

3
Wybierz urzadzenie docelowe

Na pasku gornym wybierz Android Emulator lub Windows Machine.

4
Uruchom (F5) – upewnij sie ze dziala pusty szablon

Zanim cokolwiek zmienisz – uruchom domyslny projekt. Jezeli cos sie nie kompiluje od razu, problem jest w srodowisku.

5
Dodaj folder Logika

Prawy klik na projekt -> Dodaj -> Nowy folder -> nazwij Logika. Tu beda klasy z obliczeniami.

Krok 2

3 layouty – zapamietaj te trzy

Na egzaminie uzywasz jednego lub kombinacji. Wszystkie wstawiasz jako zawartosc ContentPage w MainPage.xaml.

Layout 1 – VerticalStackLayout (najczestszy)

Elementy jeden pod drugim. Domyslny wybor gdy nie wiesz czego uzyc.

<!– Zawartosc ContentPage –> <VerticalStackLayout Padding=„20” Spacing=„12”> <Label Text=„Imie” /> <Entry x:Name=„PoleImie” Placeholder=„wpisz imie” /> <Button Text=„Zatwierdz” Clicked=„Btn_Click” /> <Label x:Name=„WynikLabel” /> </VerticalStackLayout>

Layout 2 – Grid (etykiety obok pol)

Uzywaj gdy arkusz egzaminacyjny ma tabelaryczny uklad z polami i etykietami obok siebie.

<Grid Padding=„20” RowSpacing=„10” ColumnSpacing=„12”> <Grid.RowDefinitions> <RowDefinition Height=„Auto” /> <RowDefinition Height=„Auto” /> <RowDefinition Height=„Auto” /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width=„120” /> <ColumnDefinition Width=„*” /> </Grid.ColumnDefinitions> <!– Grid.Row=wiersz (od 0), Grid.Column=kolumna (od 0) –> <Label Text=„Imie:” Grid.Row=„0” Grid.Column=„0” VerticalOptions=„Center” /> <Entry x:Name=„PoleImie” Grid.Row=„0” Grid.Column=„1” /> <Label Text=„Wiek:” Grid.Row=„1” Grid.Column=„0” VerticalOptions=„Center” /> <Entry x:Name=„PoleWiek” Grid.Row=„1” Grid.Column=„1” Keyboard=„Numeric” /> <Button Text=„Zatwierdz” Grid.Row=„2” Grid.ColumnSpan=„2” Clicked=„Btn_Click” /> </Grid>

Layout 3 – ScrollView + VerticalStackLayout (dlugi formularz)

Gdy jest duzo kontrolek i aplikacja musi przewijac zawartosc na malym ekranie.

<ScrollView> <VerticalStackLayout Padding=„20” Spacing=„14”> <Label Text=„Formularz rejestracji” FontSize=„22” FontAttributes=„Bold”/> <Entry x:Name=„PoleImie” Placeholder=„Imie”/> <!– … kolejne kontrolki … –> </VerticalStackLayout> </ScrollView>
Kontrolki

Wszystkie kontrolki – tabela podreczna

x:Name daje dostep do kontrolki z poziomu C#. Text i inne wlasciwosci ustawiasz w XAML lub z kodu.

KontrolkaDo czego sluzyJak odczytac wartosc w C#
LabelWyswietla tekst (etykieta, wynik)NazwaLabel.Text = "wynik";
EntryPole tekstowe (jeden wiersz)NazwaEntry.Text – zawsze string!
EditorPole tekstowe (wiele wierszy)NazwaEditor.Text
ButtonPrzycisk – wywoluje zdarzenieClicked="Metoda_Click"
CheckBoxPole zaznaczenia (tak/nie)NazwaCheckBox.IsChecked (bool)
SwitchPrzelacznik (wlacz/wylacz)NazwaSwitch.IsToggled (bool)
SliderSuwak (wartosc liczbowa)(int)NazwaSlider.Value – zakres Minimum/Maximum
PickerLista wyboru (dropdown)NazwaPicker.SelectedItem?.ToString()
DatePickerWybor datyNazwaDatePicker.Date (DateTime)
StepperWartosc +/-1 krok (gora/dol)(int)NazwaStepper.Value
ImageWyswietla obrazNazwaImage.Source = sciezka;
CollectionViewLista obiektow (wiele rekordow)NazwaCv.ItemsSource = lista;
BoxViewProstokat z kolorem (demo, separator)NazwaBoxView.Color = Color.FromRgb(r,g,b);
Entry.Text to zawsze string! Zeby dostac liczbe musisz skonwertowac: double.TryParse(PoleWaga.Text, out double waga). Jezeli konwersja sie nie uda – TryParse zwraca false i to jest Twoja walidacja.
Krok 3

Zdarzenia – podpiecie i odczyt danych

Szablon kazdego zdarzenia Clicked

// MainPage.xaml.cs – kazde zdarzenie wygada tak samo: private void Btn_Click(object sender, EventArgs e) { // 1. POBIERZ dane z kontrolek string imie = PoleImie.Text ?? „”; string wagaTxt = PoleWaga.Text ?? „”; // 2. SKONWERTUJ i ZWALIDUJ if (string.IsNullOrWhiteSpace(imie)) { WynikLabel.Text = „Podaj imie!”; return; } if (!double.TryParse(wagaTxt, out double waga) || waga <= 0) { WynikLabel.Text = „Waga musi byc liczba wieksza od 0!”; return; } // 3. WYWOLAJ metode z klasy Logika var kalk = new Logika.Kalkulator(); double wynik = kalk.ObliczBMI(waga, 1.75); // 4. POKAZ wynik WynikLabel.Text = $„BMI: {wynik:F1}”; }

Odczyt z roznych kontrolek – gotowe fragmenty

// Slider – suwak int r = (int)SliderR.Value; // 0-255 // CheckBox bool zgoda = CheckZgoda.IsChecked; // Switch bool aktywny = SwitchAktywny.IsToggled; // Picker string plec = PickerPlec.SelectedItem?.ToString() ?? „”; // DatePicker DateTime data = DatePickerUrodzenia.Date; int wiek = DateTime.Today.Year – data.Year; // Stepper – liczba calkowita int ilosc = (int)StepperIlosc.Value;

Slider -> zmiana koloru BoxView w czasie rzeczywistym

Zdarzenie ValueChanged odpala sie za kazdym ruchem suwaka – bez klikania przycisku.

<!– XAML –> <Label Text=„Czerwony (R)”/> <Slider x:Name=„SliderR” Minimum=„0” Maximum=„255” Value=„128” ValueChanged=„Slider_Changed”/> <Label Text=„Zielony (G)”/> <Slider x:Name=„SliderG” Minimum=„0” Maximum=„255” Value=„128” ValueChanged=„Slider_Changed”/> <Label Text=„Niebieski (B)”/> <Slider x:Name=„SliderB” Minimum=„0” Maximum=„255” Value=„128” ValueChanged=„Slider_Changed”/> <!– BoxView pokazujacy aktualny kolor –> <BoxView x:Name=„PokazKolor” HeightRequest=„80” CornerRadius=„8”/> <Label x:Name=„LabelKolor”/> <Label x:Name=„NapisKolorem” Text=„Ten napis zmienia kolor” FontSize=„18”/>
// C# – wspolna metoda dla wszystkich 3 suwaków: private void Slider_Changed(object sender, ValueChangedEventArgs e) { int r = (int)SliderR.Value; int g = (int)SliderG.Value; int b = (int)SliderB.Value; var kolor = Color.FromRgb(r, g, b); PokazKolor.Color = kolor; // tlo prostokata NapisKolorem.TextColor = kolor; // kolor napisu LabelKolor.Text = $„RGB({r}, {g}, {b})”; }
Krok 4

Osobna klasa logiki – szablon

To jest to za co dostaje sie punkty na egzaminie. Czysta klasa C# – zero importow MAUI.

Logika/Kalkulator.cs
namespace MojaApp.Logika; public class Kalkulator { /// <summary> /// Oblicza BMI na podstawie wagi i wzrostu. /// </summary> /// <param name=”wagaKg”>Waga w kilogramach</param> /// <param name=”wzrostM”>Wzrost w metrach</param> /// <returns>Wartosc BMI zaokraglona do 2 miejsc</returns> // POWYZSZY KOMENTARZ XML JEST WYMAGANY W DOKUMENTACJI! public double ObliczBMI(double wagaKg, double wzrostM) { if (wzrostM <= 0) throw new ArgumentException(„Wzrost musi byc wiekszy od 0”); return Math.Round(wagaKg / (wzrostM * wzrostM), 2); } public string InterpretujBMI(double bmi) => bmi switch { < 18.5 => „Niedowaga”, < 25.0 => „Norma”, < 30.0 => „Nadwaga”, _ => „Otylosc” }; }
Jak uzywasz klasy Logika w MainPage.xaml.cs: na poczatku pliku dodaj using MojaApp.Logika; albo uzyj pelnej nazwy: var k = new Logika.Kalkulator();
Krok 5

Lista danych + sortowanie

CollectionView to podstawa kazdej aplikacji z wieloma rekordami. Model – lista – wyswietlanie – sortowanie.

Model danych

Models/Osoba.cs
namespace MojaApp.Models; public class Osoba { public string Imie { get; set; } = „”; public string Nazwisko { get; set; } = „”; public int Wiek { get; set; } // Wlasciwosc wyliczana – nie trzeba jej zapisywac public string PelneNazwisko => $„{Imie} {Nazwisko}”; }

XAML – CollectionView z DataTemplate

<CollectionView x:Name=„ListaOsob”> <CollectionView.ItemTemplate> <DataTemplate> <VerticalStackLayout Padding=„10,6”> <Label Text=„{Binding PelneNazwisko}” FontSize=„16” FontAttributes=„Bold”/> <Label Text=„{Binding Wiek, StringFormat=’Wiek: {0} lat’}”/> </VerticalStackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> <HorizontalStackLayout Spacing=„8”> <Button Text=„A-Z” Clicked=„SortujAZ_Click”/> <Button Text=„Z-A” Clicked=„SortujZA_Click”/> <Button Text=„Wiek rosnaco” Clicked=„SortujWiek_Click”/> </HorizontalStackLayout>

C# – dane z tablicy + sortowanie

using MojaApp.Models; public partial class MainPage : ContentPage { private List<Osoba> _osoby = new(); public MainPage() { InitializeComponent(); // Dane z tablicy _osoby = new List<Osoba> { new() { Imie = „Anna”, Nazwisko = „Kowalska”, Wiek = 28 }, new() { Imie = „Bartek”, Nazwisko = „Nowak”, Wiek = 34 }, new() { Imie = „Celina”, Nazwisko = „Wisniewska”, Wiek = 22 }, new() { Imie = „Dawid”, Nazwisko = „Zajac”, Wiek = 41 }, new() { Imie = „Ewa”, Nazwisko = „Adamczyk”, Wiek = 19 }, }; OdswiezListe(_osoby); } void OdswiezListe(List<Osoba> lista) { ListaOsob.ItemsSource = null; // wymuz odswiezenie ListaOsob.ItemsSource = lista; } private void SortujAZ_Click(object s, EventArgs e) => OdswiezListe(_osoby.OrderBy(o => o.Nazwisko).ToList()); private void SortujZA_Click(object s, EventArgs e) => OdswiezListe(_osoby.OrderByDescending(o => o.Nazwisko).ToList()); private void SortujWiek_Click(object s, EventArgs e) => OdswiezListe(_osoby.OrderBy(o => o.Wiek).ToList()); }
Krok 6

Zapis i odczyt danych – TXT i JSON

Sciezka pliku w MAUI = zawsze FileSystem.AppDataDirectory! Nigdy nie uzywaj C:\Users\… ani sciezek desktopowych – na Androidzie nie istnieja i aplikacja sie wywali.

Zapis i odczyt pliku TXT

string _sciezkaTxt = Path.Combine(FileSystem.AppDataDirectory, „dane.txt”); private async void Zapisz_Click(object s, EventArgs e) { await File.WriteAllTextAsync(_sciezkaTxt, PoleEditor.Text ?? „”); StatusLabel.Text = „Zapisano!”; } private async void Wczytaj_Click(object s, EventArgs e) { if (File.Exists(_sciezkaTxt)) { PoleEditor.Text = await File.ReadAllTextAsync(_sciezkaTxt); StatusLabel.Text = „Wczytano!”; } else StatusLabel.Text = „Plik nie istnieje – najpierw zapisz.”; }

Zapis i odczyt listy obiektow jako JSON

using System.Text.Json; using MojaApp.Models; string _sciezkaJson = Path.Combine(FileSystem.AppDataDirectory, „osoby.json”); private async void ZapiszJson_Click(object s, EventArgs e) { string json = JsonSerializer.Serialize(_osoby); await File.WriteAllTextAsync(_sciezkaJson, json); StatusLabel.Text = $„Zapisano {_osoby.Count} osob.”; } private async void WczytajJson_Click(object s, EventArgs e) { if (!File.Exists(_sciezkaJson)) { StatusLabel.Text = „Brak pliku.”; return; } string json = await File.ReadAllTextAsync(_sciezkaJson); _osoby = JsonSerializer.Deserialize<List<Osoba>>(json) ?? new(); OdswiezListe(_osoby); StatusLabel.Text = $„Wczytano {_osoby.Count} osob.”; }
Przepis

Picker – lista rozwijana z danymi z kodu

Picker nie wypelnia sie w XAML – dane wkladasz z C# w konstruktorze.

<!– XAML –> <Picker x:Name=„PickerPlec” Title=„Wybierz plec”/>
// Konstruktor MainPage PickerPlec.ItemsSource = new List<string> { „Kobieta”, „Mezczyzna”, „Inne” }; // Odczyt: string plec = PickerPlec.SelectedItem?.ToString() ?? „”;
Przepis

Nawigacja – przejscie do drugiego ekranu z danymi

1
Dodaj nowa strone

Prawy klik na projekt -> Dodaj -> Nowy element -> .NET MAUI ContentPage (XAML) -> nazwij np. PodsumowaniePage.xaml

2
W App.xaml.cs ustaw NavigationPage

Zamiast AppShell: MainPage = new NavigationPage(new MainPage()); – dzieki temu Navigation.PushAsync zadziala.

3
Przejdz do drugiej strony z danych formularza

W obsludze przycisku wywolaj Navigation.PushAsync i przekaz model.

// PodsumowaniePage.xaml.cs – konstruktor przyjmuje dane public partial class PodsumowaniePage : ContentPage { public PodsumowaniePage(Osoba osoba) { InitializeComponent(); LabelImie.Text = $„Witaj, {osoba.Imie} {osoba.Nazwisko}!”; LabelWiek.Text = $„Wiek: {osoba.Wiek} lat”; } } // MainPage.xaml.cs – przejscie private async void Dalej_Click(object s, EventArgs e) { var osoba = new Osoba { Imie = PoleImie.Text ?? „”, Nazwisko = PoleNazwisko.Text ?? „”, Wiek = int.TryParse(PoleWiek.Text, out int w) ? w : 0 }; await Navigation.PushAsync(new PodsumowaniePage(osoba)); }
Aplikacja 1

Kompletna aplikacja: Rejestracja z kolorem

Formularz ze wszystkimi podstawowymi kontrolkami: Entry, Picker, Stepper, DatePicker, CheckBox i 3 suwaki RGB zmieniajace kolor napisu. Dane zapisywane do JSON.

MainPage.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=„RejestracjaApp.MainPage” Title=„Rejestracja”> <ScrollView> <VerticalStackLayout Padding=„20” Spacing=„14”> <Label Text=„Formularz rejestracji” FontSize=„22” FontAttributes=„Bold” HorizontalOptions=„Center”/> <Label Text=„Imie i nazwisko”/> <Entry x:Name=„PoleImie” Placeholder=„Jan Kowalski”/> <Label Text=„Plec”/> <Picker x:Name=„PickerPlec” Title=„Wybierz plec”/> <Label x:Name=„LabelWiek” Text=„Wiek: 18”/> <Stepper x:Name=„StepperWiek” Minimum=„10” Maximum=„99” Value=„18” Increment=„1” ValueChanged=„Stepper_Changed”/> <Label Text=„Data urodzenia”/> <DatePicker x:Name=„DataUrodzenia” Format=„yyyy-MM-dd”/> <HorizontalStackLayout Spacing=„10”> <CheckBox x:Name=„CheckZgoda”/> <Label Text=„Akceptuje regulamin” VerticalOptions=„Center”/> </HorizontalStackLayout> <BoxView HeightRequest=„1” Color=„Gray” Opacity=„0.3”/> <Label Text=„Wybierz kolor napisu” FontAttributes=„Bold”/> <Label Text=„Czerwony (R)”/> <Slider x:Name=„SliderR” Minimum=„0” Maximum=„255” Value=„100” ValueChanged=„Slider_Changed”/> <Label Text=„Zielony (G)”/> <Slider x:Name=„SliderG” Minimum=„0” Maximum=„255” Value=„150” ValueChanged=„Slider_Changed”/> <Label Text=„Niebieski (B)”/> <Slider x:Name=„SliderB” Minimum=„0” Maximum=„255” Value=„200” ValueChanged=„Slider_Changed”/> <BoxView x:Name=„PokazKolor” HeightRequest=„60” CornerRadius=„8”/> <Label x:Name=„LabelKolorRgb” HorizontalOptions=„Center”/> <Label x:Name=„NapisPowitania” Text=„Tu pojawi sie powitanie” FontSize=„18” HorizontalOptions=„Center”/> <Button Text=„Zarejestruj” Clicked=„Rejestruj_Click”/> <Button Text=„Zapisz do JSON” Clicked=„ZapiszJson_Click”/> <Button Text=„Wczytaj JSON” Clicked=„WczytajJson_Click”/> <Label x:Name=„StatusLabel” TextColor=„Gray”/> </VerticalStackLayout> </ScrollView> </ContentPage>
MainPage.xaml.cs
using System.Text.Json; using RejestracjaApp.Models; namespace RejestracjaApp; public partial class MainPage : ContentPage { private List<Osoba> _lista = new(); private string _sciezka = Path.Combine(FileSystem.AppDataDirectory, „rejestracja.json”); public MainPage() { InitializeComponent(); PickerPlec.ItemsSource = new List<string> { „Kobieta”, „Mezczyzna”, „Inne” }; AktualizujKolor(); } private void Stepper_Changed(object s, ValueChangedEventArgs e) => LabelWiek.Text = $„Wiek: {(int)StepperWiek.Value}”; private void Slider_Changed(object s, ValueChangedEventArgs e) => AktualizujKolor(); private void AktualizujKolor() { int r = (int)SliderR.Value; int g = (int)SliderG.Value; int b = (int)SliderB.Value; var kolor = Color.FromRgb(r, g, b); PokazKolor.Color = kolor; NapisPowitania.TextColor = kolor; // kolor napisu zmienia sie na zywo LabelKolorRgb.Text = $„RGB({r}, {g}, {b})”; } private void Rejestruj_Click(object s, EventArgs e) { string imie = PoleImie.Text?.Trim() ?? „”; if (string.IsNullOrEmpty(imie)) { StatusLabel.Text = „Podaj imie!”; return; } if (PickerPlec.SelectedItem == null) { StatusLabel.Text = „Wybierz plec!”; return; } if (!CheckZgoda.IsChecked) { StatusLabel.Text = „Zaakceptuj regulamin!”; return; } _lista.Add(new Osoba { Imie = imie, Plec = PickerPlec.SelectedItem.ToString()!, Wiek = (int)StepperWiek.Value, DataUrodzenia = DataUrodzenia.Date, KolorR = (int)SliderR.Value, KolorG = (int)SliderG.Value, KolorB = (int)SliderB.Value }); NapisPowitania.Text = $„Zarejestrowano: {imie}!”; StatusLabel.Text = $„Na liscie: {_lista.Count} osob.”; } private async void ZapiszJson_Click(object s, EventArgs e) { await File.WriteAllTextAsync(_sciezka, JsonSerializer.Serialize(_lista)); StatusLabel.Text = $„Zapisano {_lista.Count} rekordow.”; } private async void WczytajJson_Click(object s, EventArgs e) { if (!File.Exists(_sciezka)) { StatusLabel.Text = „Brak pliku.”; return; } string json = await File.ReadAllTextAsync(_sciezka); _lista = JsonSerializer.Deserialize<List<Osoba>>(json) ?? new(); StatusLabel.Text = $„Wczytano {_lista.Count} rekordow.”; } } // Models/Osoba.cs namespace RejestracjaApp.Models; public class Osoba { public string Imie { get; set; } = „”; public string Plec { get; set; } = „”; public int Wiek { get; set; } public DateTime DataUrodzenia { get; set; } public int KolorR { get; set; } public int KolorG { get; set; } public int KolorB { get; set; } }
Aplikacja 2

Kompletna aplikacja: Lista + sortowanie + JSON

Dane z tablicy -> CollectionView -> sortowanie alfabetyczne i po wartosci -> eksport JSON. Wzorzec na kazde zadanie egzaminacyjne z lista.

MainPage.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=„SortowanieApp.MainPage” Title=„Lista i sortowanie”> <VerticalStackLayout Padding=„16” Spacing=„10”> <Label Text=„Dodaj osobe” FontAttributes=„Bold”/> <Entry x:Name=„PoleImie” Placeholder=„Imie”/> <Entry x:Name=„PoleNazwisko” Placeholder=„Nazwisko”/> <Entry x:Name=„PoleWiek” Placeholder=„Wiek” Keyboard=„Numeric”/> <Button Text=„+ Dodaj” Clicked=„Dodaj_Click”/> <HorizontalStackLayout Spacing=„6”> <Button Text=„A-Z” Clicked=„SortAZ_Click”/> <Button Text=„Z-A” Clicked=„SortZA_Click”/> <Button Text=„Wiek” Clicked=„SortWiek_Click”/> <Button Text=„Reset” Clicked=„Reset_Click”/> </HorizontalStackLayout> <HorizontalStackLayout Spacing=„6”> <Button Text=„Zapisz JSON” Clicked=„Zapisz_Click”/> <Button Text=„Wczytaj JSON” Clicked=„Wczytaj_Click”/> </HorizontalStackLayout> <Label x:Name=„StatusLabel” TextColor=„Gray”/> <CollectionView x:Name=„ListaOsob”> <CollectionView.ItemTemplate> <DataTemplate> <Grid Padding=„10,6” ColumnDefinitions=„*,Auto”> <VerticalStackLayout Grid.Column=„0”> <Label Text=„{Binding PelneNazwisko}” FontAttributes=„Bold”/> <Label Text=„{Binding Wiek, StringFormat=’Wiek: {0} lat’}” TextColor=„Gray”/> </VerticalStackLayout> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </ContentPage>
MainPage.xaml.cs
using System.Text.Json; using SortowanieApp.Models; namespace SortowanieApp; public partial class MainPage : ContentPage { private List<Osoba> _oryginalna = new(); private string _sciezka = Path.Combine(FileSystem.AppDataDirectory, „osoby.json”); public MainPage() { InitializeComponent(); _oryginalna = new List<Osoba> { new() { Imie=„Anna”, Nazwisko=„Kowalska”, Wiek=28 }, new() { Imie=„Bartek”, Nazwisko=„Nowak”, Wiek=34 }, new() { Imie=„Celina”, Nazwisko=„Wisniewska”, Wiek=22 }, new() { Imie=„Dawid”, Nazwisko=„Zajac”, Wiek=41 }, new() { Imie=„Ewa”, Nazwisko=„Adamczyk”, Wiek=19 }, }; Odswierz(_oryginalna); } void Odswierz(List<Osoba> lista) { ListaOsob.ItemsSource = null; ListaOsob.ItemsSource = lista; StatusLabel.Text = $„Rekordow: {lista.Count}”; } private void Dodaj_Click(object s, EventArgs e) { string imie = PoleImie.Text?.Trim() ?? „”; string nazw = PoleNazwisko.Text?.Trim() ?? „”; if (string.IsNullOrEmpty(imie) || string.IsNullOrEmpty(nazw)) { StatusLabel.Text = „Podaj imie i nazwisko!”; return; } if (!int.TryParse(PoleWiek.Text, out int wiek) || wiek < 1) { StatusLabel.Text = „Wiek musi byc liczba!”; return; } _oryginalna.Add(new() { Imie = imie, Nazwisko = nazw, Wiek = wiek }); PoleImie.Text = PoleNazwisko.Text = PoleWiek.Text = „”; Odswierz(_oryginalna); } private void SortAZ_Click(object s, EventArgs e) => Odswierz(_oryginalna.OrderBy(o => o.Nazwisko).ToList()); private void SortZA_Click(object s, EventArgs e) => Odswierz(_oryginalna.OrderByDescending(o => o.Nazwisko).ToList()); private void SortWiek_Click(object s, EventArgs e) => Odswierz(_oryginalna.OrderBy(o => o.Wiek).ToList()); private void Reset_Click(object s, EventArgs e) => Odswierz(_oryginalna); private async void Zapisz_Click(object s, EventArgs e) { await File.WriteAllTextAsync(_sciezka, JsonSerializer.Serialize(_oryginalna)); StatusLabel.Text = $„Zapisano {_oryginalna.Count} rekordow.”; } private async void Wczytaj_Click(object s, EventArgs e) { if (!File.Exists(_sciezka)) { StatusLabel.Text = „Brak pliku.”; return; } string json = await File.ReadAllTextAsync(_sciezka); _oryginalna = JsonSerializer.Deserialize<List<Osoba>>(json) ?? new(); Odswierz(_oryginalna); } } // Models/Osoba.cs namespace SortowanieApp.Models; public class Osoba { public string Imie { get; set; } = „”; public string Nazwisko { get; set; } = „”; public int Wiek { get; set; } public string PelneNazwisko => $„{Imie} {Nazwisko}”; }
Testy

Test jednostkowy MSTest – schemat

1
Dodaj projekt testowy do solucji

Prawy klik na solucie (nie projekt!) -> Dodaj -> Nowy projekt -> MSTest Test Project (.NET)

2
Dodaj referencje do projektu MAUI

Prawy klik na projekt testowy -> Dodaj -> Odwolanie do projektu -> zaznacz projekt MAUI

3
Napisz test i uruchom (Ctrl+R, A)

Testujesz metode z klasy Logika – nie testujesz UI.

using Microsoft.VisualStudio.TestTools.UnitTesting; using MojaApp.Logika; [TestClass] public class KalkulatorTests { // Schemat AAA: Arrange – Act – Assert [TestMethod] public void ObliczBMI_PoprawneWartosci_ZwracaPoprawneBMI() { // Arrange var kalk = new Kalkulator(); // Act double wynik = kalk.ObliczBMI(70, 1.75); // Assert Assert.AreEqual(22.86, wynik, delta: 0.01); } [TestMethod] public void ObliczBMI_ZeroWzrost_RzucaWyjatek() { var kalk = new Kalkulator(); Assert.ThrowsException<ArgumentException>(() => kalk.ObliczBMI(70, 0)); } }
Przed oddaniem

Checklista – sprawdz zanim spakujesz ZIP

Aplikacja

  • Projekt kompiluje sie bez bledow
  • Aplikacja uruchamia sie na emulatorze
  • Interfejs zgodny z projektem z arkusza
  • Logika obliczeniowa w osobnej klasie
  • Walidacja pokazuje komunikat przy zlych danych
  • Zapis uzywa FileSystem.AppDataDirectory
  • Odczyt dziala po ponownym uruchomieniu
  • Brak sciezek bezwzglednych (C:\Users\…)

Dokumentacja i testy

  • Zrzuty ekranu z dzialajcej aplikacji (min 2)
  • Opis srodowiska: VS 2022, .NET MAUI, Android
  • Komentarz XML nad metoda z numerem zdajacego
  • Tabela przypadkow testowych (dane – wynik)
  • Projekt MSTest z co najmniej jednym testem
  • Test uruchamia sie i przechodzi (zielony)
  • Projekt spakowany do ZIP
  • Nazwa ZIP zgodna z numerem zdajacego
Najczestsze straty punktow: brak komentarza XML do metody, sciezka bezwzgledna do pliku, logika obliczeniowa w obsludze przycisku zamiast w osobnej klasie, brak zrzutow ekranu. To sa punkty do wziecia bez zadnego wysilku – tylko pamietaj o nich przed oddaniem.
.NET MAUI · INF.04 · bitedu.pl · technik programisty

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *