1. Co to są modele i po co je stosujemy?
Wyjaśnienie prostymi słowami
Wyobraź sobie, że piszesz aplikację „Formularz zdrowia” — gdzie użytkownik wpisuje imię, wzrost, wagę, płeć. Możesz trzymać te wartości w zmiennych rozsianych po różnych miejscach w kodzie — ale to będzie bałagan. Znacznie lepiej jest stworzyć model, czyli klasę, która zgromadzi wszystkie dane w jednym obiekcie.
To tak, jak mieć teczkę pacjenta w przychodni — w niej imię, wiek, wyniki badań. Nie trzy luźne kartki, ale uporządkowana teczka.
Co model powinien zawierać?
- Właściwości (properties) odpowiadające danym z formularza
- Jeśli to sensowne, metody związane z danymi (np.
ObliczBmi()w klasie modelu)
Model nie powinien zawierać kodu, który obsługuje interfejs użytkownika (np. MessageBox.Show), ani walidacji interfejsowej — to będzie osobna część.
2. Co to jest walidacja?
Walidacja to sprawdzanie, czy dane wpisane przez użytkownika są poprawne i sensowne, zanim je użyjesz.
Przykłady:
- Imię nie może być puste
- Wzrost musi być liczbą większą niż zero
- Waga musi być liczbą i mieścić się w rozsądnym zakresie
- Płeć powinna być spośród dostępnych opcji
Dlaczego to ważne?
- Zabezpiecza przed błędami (np. dzielenie przez zero)
- Użytkownik od razu wie, co wpisał źle
- Program jest bardziej odporny na „dziwne” dane
Walidację też dobrze oddzielić od interfejsu — czyli zrobić klasy/metody walidacyjne, które dostają teksty z kontrolek, a zwracają listę błędów lub gotowy model.
3. Struktura folderów i plików (propozycja)
Załóżmy, że twoja aplikacja to „FormularzZdrowia”. Oto jak możesz zorganizować:
FormularzZdrowia/
│
├── Modele/
│ └── DaneFormularza.cs
│ └── Plec.cs
│
├── Walidacja/
│ └── Walidacje.cs
│ └── WalidatorFormularza.cs
│
├── MainWindow.xaml
└── MainWindow.xaml.cs
– Modele to miejsce dla klas, które trzymają dane
– Walidacja to miejsce dla klas/metod sprawdzających dane
– MainWindow.xaml + .cs to warstwa interfejsu użytkownika
4. Kod krok po kroku
Poniżej najprostszy przykład, który będzie wystarczający na egzamin — bez wzorców MVVM, lecz z wyraźnym oddzieleniem modelu i walidacji.
Plik: Modele/Plec.cs
namespace FormularzZdrowia.Modele
{
public enum Plec
{
NiePodano,
Kobieta,
Mezczyzna
}
}
(To enum — typ wyliczeniowy dla płci.)
Plik: Modele/DaneFormularza.cs
namespace FormularzZdrowia.Modele
{
public class DaneFormularza
{
public string Imie { get; set; } = "";
public double? WzrostCm { get; set; }
public double? WagaKg { get; set; }
public Plec Plec { get; set; } = Plec.NiePodano;
public double? ObliczBmi()
{
if (WzrostCm is null || WagaKg is null) return null;
double wzrostM = WzrostCm.Value / 100.0;
if (wzrostM <= 0) return null;
return Math.Round(WagaKg.Value / (wzrostM * wzrostM), 2);
}
}
}
double?oznacza typ, który może być pusty (null) — to pomaga, gdy wpis użytkownika nie jest jeszcze poprawnyObliczBmizwracanull, jeśli nie da się obliczyć
Plik: Walidacja/Walidacje.cs
Tutaj umieszczamy małe, pomocnicze metody, które przydadzą się wielokrotnie.
using System.Globalization;
namespace FormularzZdrowia.Walidacja
{
public static class Walidacje
{
public static bool NiePuste(string? txt) =>
!string.IsNullOrWhiteSpace(txt);
public static double? SprobujDouble(string? txt)
{
if (string.IsNullOrWhiteSpace(txt))
return null;
// Parsowanie z polską kulturą (przecinek jako separator)
if (double.TryParse(txt, NumberStyles.Float, new CultureInfo("pl-PL"), out double val))
return val;
return null;
}
public static bool WZakresie(double? wartość, double min, double max) =>
wartość is not null && wartość >= min && wartość <= max;
}
}
Plik: Walidacja/WalidatorFormularza.cs
To klasa, która zbiera wszystkie sprawdzenia w jednym miejscu. Weź dane (jako teksty) i sprawdź, czy są ok. Zwróć wynik + ewentualne błędy + gotowy model (jeśli wszystko OK).
using System;
using System.Collections.Generic;
using FormularzZdrowia.Modele;
namespace FormularzZdrowia.Walidacja
{
public static class WalidatorFormularza
{
public static (bool ok, List<string> bledy, DaneFormularza? model)
SprawdzIZbuduj(string? imieTxt, string? wzrostTxt, string? wagaTxt, string? plecTxt)
{
List<string> bledy = new List<string>();
// Imię
if (!Walidacje.NiePuste(imieTxt))
bledy.Add("Imię nie może być puste.");
else if (imieTxt!.Trim().Length < 2)
bledy.Add("Imię musi mieć co najmniej 2 znaki.");
// Wzrost
var wzrost = Walidacje.SprobujDouble(wzrostTxt);
if (wzrost is null)
bledy.Add("Wzrost musi być liczbą.");
else if (!Walidacje.WZakresie(wzrost, 50, 300))
bledy.Add("Wzrost musi być między 50 a 300 cm.");
// Waga
var waga = Walidacje.SprobujDouble(wagaTxt);
if (waga is null)
bledy.Add("Waga musi być liczbą.");
else if (!Walidacje.WZakresie(waga, 10, 400))
bledy.Add("Waga musi być między 10 a 400 kg.");
// Płeć
Plec plec = Plec.NiePodano;
if (!string.IsNullOrWhiteSpace(plecTxt))
{
if (Enum.TryParse<Plec>(plecTxt, ignoreCase: true, out Plec wynik))
plec = wynik;
else
bledy.Add("Niepoprawna wartość płci.");
}
if (bledy.Count > 0)
return (false, bledy, null);
// Wszystko OK — twórz model
DaneFormularza model = new DaneFormularza
{
Imie = imieTxt!.Trim(),
WzrostCm = wzrost,
WagaKg = waga,
Plec = plec
};
return (true, bledy, model);
}
}
}
Plik: MainWindow.xaml
To nasz interfejs graficzny — okno z polami do wpisywania i przyciskiem „Wyślij”.
<Window x:Class="FormularzZdrowia.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Formularz Zdrowia" Height="300" Width="350">
<StackPanel Margin="20">
<TextBlock Text="Imię:" />
<TextBox x:Name="txtImie" Margin="0,5"/>
<TextBlock Text="Wzrost (cm):" />
<TextBox x:Name="txtWzrost" Margin="0,5"/>
<TextBlock Text="Waga (kg):" />
<TextBox x:Name="txtWaga" Margin="0,5"/>
<TextBlock Text="Płeć:" />
<TextBox x:Name="txtPlec" Margin="0,5" PlaceholderText="NiePodano / Kobieta / Mezczyzna"/>
<Button Content="Wyślij" Margin="0,10" Click="Wyślij_Click"/>
<TextBlock x:Name="txtBledy" Foreground="Red" TextWrapping="Wrap" />
</StackPanel>
</Window>
Plik: MainWindow.xaml.cs
To kod, który reaguje na kliknięcie, używa walidatora i pokazuje wynik albo błędy.
using System.Windows;
using FormularzZdrowia.Modele;
using FormularzZdrowia.Walidacja;
namespace FormularzZdrowia
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Wyślij_Click(object sender, RoutedEventArgs e)
{
// 1. Zbierz teksty z kontrolek
string imieTxt = txtImie.Text;
string wzrostTxt = txtWzrost.Text;
string wagaTxt = txtWaga.Text;
string plecTxt = txtPlec.Text;
// 2. Walidacja i zbudowanie modelu
var (ok, bledy, model) = WalidatorFormularza.SprawdzIZbuduj(imieTxt, wzrostTxt, wagaTxt, plecTxt);
if (!ok)
{
// Wyświetl błędy — jedno pod drugim
txtBledy.Text = "Błędy:\n" + string.Join("\n", bledy);
return;
}
// 3. Jeśli dane poprawne, pokaz podsumowanie
// Możemy użyć MessageBox lub otworzyć nowe okno — tu dla uproszczenia:
double? bmi = model!.ObliczBmi();
string wynik = bmi is null ? "Nie można obliczyć BMI" : bmi.Value.ToString("0.00");
MessageBox.Show(
$"Imię: {model.Imie}\n" +
$"Wzrost: {model.WzrostCm} cm\n" +
$"Waga: {model.WagaKg} kg\n" +
$"Płeć: {model.Plec}\n" +
$"BMI: {wynik}",
"Podsumowanie");
}
}
}
5. Zadania dla uczniów (do samodzielnego zrobienia)
- Rozszerz aplikację o pole Wiek (int).
- Dodaj do
DaneFormularzawłaściwośćWiek(int?). - W walidatorze sprawdź, że wiek jest liczbą całkowitą i w rozsądnym zakresie (np. 0–120).
- W podsumowaniu pokaż „Wiek: X lat”.
- Dodaj do
- Zamiast pola
txtPlecjako zwykłegoTextBox, zmień je naComboBoxz opcjami: „NiePodano”, „Kobieta”, „Mezczyzna”.- W
MainWindow.xamlużyj<ComboBox>i odczytajSelectedItemlubSelectedValuewWyślij_Click. - Sprawdź, czy wybrana wartość prawidłowo przechodzi walidację i trafia do modelu.
- W
- Utwórz nowe okno
Window(np.PodsumowanieWindow) i wyświetl dane zmodeltam zamiast MessageBox.- W konstruktorze okna przekaż
DaneFormularza model. - W XAML tego nowego okna umieść
TextBlock-y, aby pokazać Imię, Wzrost, Waga, Płeć, BMI.
- W konstruktorze okna przekaż

