Wprowadzenie
Podczas tworzenia aplikacji bardzo często musimy pracować z danymi, które użytkownik wpisuje w formularzach (np. imię, wzrost, waga, płeć).
Żeby te dane były uporządkowane i łatwe do obsługi, wprowadzamy modele – specjalne klasy, które przechowują dane.
Dodatkowo, zanim dane zostaną użyte (np. wyświetlone, zapisane, wysłane do bazy), trzeba je sprawdzić, czyli wykonać walidację. Dzięki temu aplikacja nie przyjmie błędnych wartości (np. pustego imienia albo wzrostu 0 cm).
Co to są modele?
- Model to klasa w C#, która opisuje dane.
- Zawiera tylko pola/properties (np. Imię, Wzrost, Waga, Płeć).
- Dzięki modelowi możemy dane przekazywać jako całość, a nie w postaci wielu pojedynczych zmiennych.
Przykład modelu z naszej aplikacji:
public class DaneFormularza
{
public string Imie { get; set; } = "";
public double? WzrostCm { get; set; }
public double? WagaKg { get; set; }
public string Plec { get; set; } = "Nie podano";
}Co nam dają modele?
- Porządek w kodzie – dane są w jednym miejscu, a nie rozsypane po formularzu.
- Łatwe przekazywanie – można przesłać cały model między ekranami (new DanePage(model)).
- Obiektowość – uczymy się myślenia w kategoriach klas i obiektów, co jest wymagane na egzaminie INF.04.
- Możliwość rozbudowy – w przyszłości można do modelu dodać metody (np. oblicz BMI).
Walidacja danych
Walidacja to proces sprawdzania poprawności danych wpisanych przez użytkownika.
W naszej aplikacji zrobiliśmy osobną klasę WalidatorFormularza, która:
- sprawdza, czy imię nie jest puste,
- sprawdza, czy wzrost i waga są liczbami i w odpowiednim zakresie,
- zwraca listę błędów, które pokazujemy użytkownikowi w komunikacie.
Fragment walidacji:
public static (bool ok, List<string> bledy) Sprawdz(string? imieTxt, string? wzrostTxt, string? wagaTxt)
{
var bledy = new List<string>();
if (string.IsNullOrWhiteSpace(imieTxt))
bledy.Add("Podaj imię.");
var wzrost = SprobujLiczbe(wzrostTxt);
if (wzrost is null) bledy.Add("Wzrost musi być liczbą.");
else if (wzrost <= 0 || wzrost > 300) bledy.Add("Wzrost w zakresie 1–300 cm.");
var waga = SprobujLiczbe(wagaTxt);
if (waga is null) bledy.Add("Waga musi być liczbą.");
else if (waga <= 0 || waga > 400) bledy.Add("Waga w zakresie 1–400 kg.");
return (bledy.Count == 0, bledy);
}Jak to wygląda w aplikacji?
- Użytkownik wypełnia formularz (Imię, Wzrost, Waga, Płeć).
- Kliknięcie „Wyślij” wywołuje walidację:
- jeśli są błędy → komunikat DisplayAlert z listą błędów,
- jeśli wszystko poprawne → tworzymy obiekt DaneFormularza i przechodzimy na ekran podsumowania.
- Na trzecim ekranie dane z modelu są wyświetlane w etykietach (Label).
Podsumowanie
- Model = klasa opisująca dane (np. DaneFormularza).
- Walidacja = sprawdzanie, czy dane mają sens, zanim je użyjemy.
- Dzięki modelom i walidacji aplikacje są bardziej uporządkowane, bezpieczne i czytelne.
- To podejście jest zgodne z wymaganiami egzaminu INF.04 – rozdzielenie warstw aplikacji, stosowanie klas i obiektów oraz dbanie o poprawność danych.
Przykład zadania z modelami. Dwa formularze i podsumowanie: gotowy kod:
Struktura
MauiTrzyOkna/
├── App.xaml
├── App.xaml.cs
├── AppShell.xaml
├── AppShell.xaml.cs
├── MauiProgram.cs
├── Models/
│ └── Dane.cs
├── MainPage.xaml
├── MainPage.xaml.cs
├── Strona2.xaml
├── Strona2.xaml.cs
├── Podsumowanie.xaml
└── Podsumowanie.xaml.cs
1) App.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Application
x:Class="MauiTrzyOkna.App"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<!-- Tu możesz wrzucać style, jeśli chcesz -->
</Application>
2) App.xaml.cs
using MauiTrzyOkna.Models;
namespace MauiTrzyOkna;
public partial class App : Application
{
// Współdzielone dane dla wszystkich stron (prosto pod egzamin):
public static Dane Dane { get; } = new();
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
}
3) AppShell.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MauiTrzyOkna.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiTrzyOkna">
<TabBar>
<ShellContent Title="Formularz 1" ContentTemplate="{DataTemplate local:MainPage}" Route="main" />
<ShellContent Title="Formularz 2" ContentTemplate="{DataTemplate local:Strona2}" Route="strona2" />
<ShellContent Title="Podsumowanie" ContentTemplate="{DataTemplate local:Podsumowanie}" Route="podsumowanie" />
</TabBar>
</Shell>
4) AppShell.xaml.cs
namespace MauiTrzyOkna;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
5) MauiProgram.cs
namespace MauiTrzyOkna;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
return builder.Build();
}
}
6) Models/Dane.cs
namespace MauiTrzyOkna.Models;
public class Dane
{
// Formularz 1 (3 pola)
public string Imie { get; set; } = "";
public string Nazwisko { get; set; } = "";
public string Email { get; set; } = "";
// Formularz 2 (2 pola)
public int? Wiek { get; set; }
public string Miasto { get; set; } = "";
}
7) MainPage.xaml (Formularz 1 – 3 pola)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MauiTrzyOkna.MainPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Formularz 1">
<ScrollView>
<VerticalStackLayout Padding="16" Spacing="12">
<Label Text="Imię" />
<Entry Text="{Binding Imie, Mode=TwoWay}" Placeholder="Wpisz imię" />
<Label Text="Nazwisko" />
<Entry Text="{Binding Nazwisko, Mode=TwoWay}" Placeholder="Wpisz nazwisko" />
<Label Text="E-mail" />
<Entry Text="{Binding Email, Mode=TwoWay}" Keyboard="Email" Placeholder="np. jan@domena.pl" />
<Button Text="Przejdź do Formularza 2" Clicked="PrzejdzDoStrony2_Clicked" />
<Button Text="Podsumowanie" Clicked="Podsumowanie_Clicked" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
8) MainPage.xaml.cs
namespace MauiTrzyOkna;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = App.Dane;
}
private async void PrzejdzDoStrony2_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//strona2");
private async void Podsumowanie_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//podsumowanie");
}
9) Strona2.xaml (Formularz 2 – 2 pola)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MauiTrzyOkna.Strona2"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Formularz 2">
<ScrollView>
<VerticalStackLayout Padding="16" Spacing="12">
<Label Text="Wiek" />
<Entry Text="{Binding Wiek, Mode=TwoWay}" Keyboard="Numeric" Placeholder="np. 18" />
<Label Text="Miasto" />
<Entry Text="{Binding Miasto, Mode=TwoWay}" Placeholder="np. Działdowo" />
<Button Text="Zapisz i pokaż Podsumowanie" Clicked="Podsumowanie_Clicked" />
<Button Text="Wróć do Formularza 1" Clicked="WrocDoForm1_Clicked" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
10) Strona2.xaml.cs
namespace MauiTrzyOkna;
public partial class Strona2 : ContentPage
{
public Strona2()
{
InitializeComponent();
BindingContext = App.Dane;
}
private async void Podsumowanie_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//podsumowanie");
private async void WrocDoForm1_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//main");
}
11) Podsumowanie.xaml (wyświetlenie wszystkiego — poprawny Grid)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MauiTrzyOkna.Podsumowanie"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Podsumowanie">
<ScrollView>
<VerticalStackLayout Padding="16" Spacing="12">
<Label FontAttributes="Bold" FontSize="20" Text="Zebrane dane" />
<Grid ColumnDefinitions="120,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
RowSpacing="6">
<Label Text="Imię:" Grid.Column="0" Grid.Row="0" />
<Label Text="{Binding Imie}" Grid.Column="1" Grid.Row="0" />
<Label Text="Nazwisko:" Grid.Column="0" Grid.Row="1" />
<Label Text="{Binding Nazwisko}" Grid.Column="1" Grid.Row="1" />
<Label Text="E-mail:" Grid.Column="0" Grid.Row="2" />
<Label Text="{Binding Email}" Grid.Column="1" Grid.Row="2" />
<Label Text="Wiek:" Grid.Column="0" Grid.Row="3" />
<Label Text="{Binding Wiek}" Grid.Column="1" Grid.Row="3" />
<Label Text="Miasto:" Grid.Column="0" Grid.Row="4" />
<Label Text="{Binding Miasto}" Grid.Column="1" Grid.Row="4" />
</Grid>
<Button Text="Edytuj Formularz 1" Clicked="DoForm1_Clicked" />
<Button Text="Edytuj Formularz 2" Clicked="DoForm2_Clicked" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
12) Podsumowanie.xaml.cs
namespace MauiTrzyOkna;
public partial class Podsumowanie : ContentPage
{
public Podsumowanie()
{
InitializeComponent();
BindingContext = App.Dane;
}
private async void DoForm1_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//main");
private async void DoForm2_Clicked(object sender, EventArgs e)
=> await Shell.Current.GoToAsync("//strona2");
}

