Aplikacje desktopowe · Dane
Modele danych i walidacja formularzy
Formularze mają zwykle wiele pól, a dane z nich trzeba uporządkować i sprawdzić, zanim ich użyjesz. Poznasz model danych (klasę grupującą informacje) i walidację, czyli sprawdzanie poprawności, tak aby program nie „wywracał się” na błędnym wpisie.
- około 50 minut
- WPF · model · walidator · TryParse
- INF.04.5.3
Po tej lekcji: zbudować klasę modelu z właściwościami, napisać osobny walidator zwracający listę błędów i bezpiecznie zamienić tekst na liczbę przez TryParse.
Zacznijmy od teczki
Teczka pacjenta zamiast trzech karteczek
W aplikacji „Formularz zdrowia” użytkownik wpisuje imię, wzrost i wagę. Można trzymać te wartości w luźnych zmiennych rozsianych po kodzie, ale to bałagan. Lepiej zebrać je w model: jedną klasę, która grupuje powiązane dane, jak teczka pacjenta w przychodni.
Z kolei walidacja to sprawdzenie, czy wpisane dane mają sens, zanim ich użyjesz. Chroni przed błędami (np. dzieleniem przez zero) i od razu mówi użytkownikowi, co poprawić.
1 · Podział odpowiedzialności
Model trzyma dane, walidator je sprawdza
Modelfolder Modele
Klasa z właściwościami odpowiadającymi polom formularza i metodami bezpośrednio związanymi z tymi danymi, np. ObliczBmi(). Nie zna okna i nie pokazuje komunikatów.
Na przykład DaneFormularza
Walidatorfolder Walidacja
Osobna klasa, która przyjmuje model i zwraca listę błędów (pustą, gdy wszystko jest poprawne). Nie pokazuje ich: to robi okno.
Na przykład WalidatorFormularza.Sprawdz(dane)
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
2 · Sprawdź w działaniu
Co się stanie przy błędnych danych
Formularz startuje z błędnymi danymi (puste imię, wzrost 0, waga „abc”). Kliknij „Oblicz BMI” i obejrzyj model i listę błędów. Potem przełącz walidator na „tylko pierwszy błąd” oraz zamianę na double.Parse, i zobacz, jak program się wywraca.
Zbieraj wszystkie błędy naraz, a tekst zamieniaj na liczbę przez TryParse. Użytkownik poprawi wszystko w jednym podejściu, a program się nie wywróci.
3 · Dane
DaneFormularza.cs
Model to zwykła klasa C#: trzy właściwości i jedna metoda związana z tymi danymi. Żadnych odwołań do okna.
namespace FormularzZdrowia.Modele;
public class DaneFormularza
{
public string Imie { get; set; } = "";
public double WzrostCm { get; set; }
public double WagaKg { get; set; }
// Metoda związana z danymi modelu: to jest w porządku w modelu
public double ObliczBmi()
{
double wzrostM = WzrostCm / 100.0;
return WagaKg / (wzrostM * wzrostM);
}
}
{ get; set; }Właściwość automatyczna: do odczytu i zapisu. Wartość domyślna""zapobieganull.ObliczBmi()Metoda należąca do danych: BMI = waga podzielona przez wzrost w metrach podniesiony do kwadratu.WzrostCm / 100.0Dzielimy przez100.0, a nie100, żeby wynik był liczbą rzeczywistą.
4 · Reguły
WalidatorFormularza.cs
Walidator zwraca listę komunikatów. Dzięki temu okno pokaże wszystkie problemy naraz, a nie tylko pierwszy.
using System.Collections.Generic;
using FormularzZdrowia.Modele;
namespace FormularzZdrowia.Walidacja;
public class WalidatorFormularza
{
public List<string> Sprawdz(DaneFormularza dane)
{
var bledy = new List<string>();
if (string.IsNullOrWhiteSpace(dane.Imie))
{
bledy.Add("Imię nie może być puste.");
}
if (dane.WzrostCm <= 0 || dane.WzrostCm > 250)
{
bledy.Add("Wzrost musi być liczbą z zakresu 1-250 cm.");
}
if (dane.WagaKg <= 0 || dane.WagaKg > 300)
{
bledy.Add("Waga musi być liczbą z zakresu 1-300 kg.");
}
return bledy; // pusta lista oznacza, że dane są poprawne
}
}
List<string> bledyZbiera komunikaty. Pusta lista oznacza poprawne dane.string.IsNullOrWhiteSpaceWykrywa puste pole i pole z samymi spacjami.dane.WzrostCm <= 0 || dane.WzrostCm > 250Reguła zakresu: wzrost musi być sensowny.return bledyWalidator niczego nie wyświetla. Ta decyzja należy do okna.
5 · Cały przepływ
MainWindow.xaml.cs
Kolejność jest zawsze ta sama: zbuduj model, sprawdź go walidatorem, a dopiero przy poprawnych danych wykonaj obliczenie.
using System.Windows;
using FormularzZdrowia.Modele;
using FormularzZdrowia.Walidacja;
namespace FormularzZdrowia;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void PrzyciskOblicz_Click(object sender, RoutedEventArgs e)
{
var dane = new DaneFormularza
{
Imie = PoleImie.Text,
WzrostCm = double.TryParse(PoleWzrost.Text, out var w) ? w : 0,
WagaKg = double.TryParse(PoleWaga.Text, out var m) ? m : 0
};
var walidator = new WalidatorFormularza();
var bledy = walidator.Sprawdz(dane);
if (bledy.Count > 0)
{
EtykietaWynik.Text = "Błędy: " + string.Join(" ", bledy);
return;
}
EtykietaWynik.Text = $"BMI dla {dane.Imie}: {dane.ObliczBmi():F1}";
}
}
double.TryParse(PoleWzrost.Text, out var w) ? w : 0Próbuje zamienić tekst na liczbę. Gdy się nie uda, zwraca0, więc program się nie wywraca, a walidator zgłosi błąd.walidator.Sprawdz(dane)Walidacja gotowego obiektu modelu.if (bledy.Count > 0) { ...; return; }Przy błędach pokazujemy je i kończymy metodę, nie licząc BMI.{dane.ObliczBmi():F1}Wynik z jednym miejscem po przecinku.
Do zadań
Zbieranie wszystkich błędów i pokazanie ich razem
W zadaniach walidator ma zgłosić wszystkie złamane reguły. Zamiast kończyć na pierwszym błędzie, dodawaj komunikaty do listy i wyświetl ją na końcu.
using System.Linq; // dla Any
public static List<string> Sprawdz(string imie, string haslo, string powtorzenie, string wiekTekst)
{
var bledy = new List<string>();
if (imie.Trim().Length < 2)
bledy.Add("Imię ma mieć co najmniej 2 znaki.");
if (imie.Any(char.IsDigit)) // czy jakikolwiek znak jest cyfrą
bledy.Add("Imię nie może zawierać cyfr.");
if (haslo.Length < 8)
bledy.Add("Hasło ma mieć co najmniej 8 znaków.");
if (haslo != powtorzenie)
bledy.Add("Hasła muszą być identyczne.");
if (!int.TryParse(wiekTekst, out int wiek) || wiek < 13 || wiek > 120)
bledy.Add("Wiek ma być liczbą od 13 do 120.");
return bledy;
}
// w oknie: każdy błąd w nowej linii
var bledy = WalidatorFormularza.Sprawdz(...);
EtykietaBledy.Text = string.Join(Environment.NewLine, bledy);
imie.Any(char.IsDigit)Przechodzi po wszystkich znakach i sprawdza, czy któryś jest cyfrą.string.Join(Environment.NewLine, bledy)Skleja listę w jeden napis, wstawiając koniec linii między elementami.- Pusta lista Brak błędów (
bledy.Count == 0) oznacza, że dane są poprawne.
6 · Wygląd
MainWindow.xaml
Trzy pola, przycisk i etykieta na wynik lub błędy. Zwykły widok bez logiki.
<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="320" Width="360">
<StackPanel Margin="20">
<TextBlock Text="Imię:" />
<TextBox x:Name="PoleImie" Margin="0,2,0,8" />
<TextBlock Text="Wzrost (cm):" />
<TextBox x:Name="PoleWzrost" Margin="0,2,0,8" />
<TextBlock Text="Waga (kg):" />
<TextBox x:Name="PoleWaga" Margin="0,2,0,12" />
<Button Content="Oblicz BMI" Click="PrzyciskOblicz_Click" />
<TextBlock x:Name="EtykietaWynik" TextWrapping="Wrap" Margin="0,12,0,0" />
</StackPanel>
</Window>
TextWrapping="Wrap"Długa lista błędów zawija się do kolejnych linii zamiast wychodzić poza okno.
7 · Czego unikać
Trzy błędy z walidacją
`MessageBox` w walidatorze
public bool Sprawdz(DaneFormularza dane)
{
if (dane.WzrostCm <= 0)
{
MessageBox.Show("Zły wzrost");
return false;
}
return true;
}Walidatora nie da się przetestować ani użyć poza oknem, a komunikat jest „na sztywno”.
public List<string> Sprawdz(DaneFormularza dane)
{
var bledy = new List<string>();
if (dane.WzrostCm <= 0) bledy.Add("Zły wzrost");
return bledy;
}Walidator zwraca informację, a okno decyduje, jak ją pokazać.
Tylko pierwszy błąd
if (string.IsNullOrWhiteSpace(dane.Imie)) return "Brak imienia";
if (dane.WzrostCm <= 0) return "Zły wzrost";Użytkownik poprawia jedno pole i dopiero wtedy widzi kolejny błąd.
var bledy = new List<string>();
if (string.IsNullOrWhiteSpace(dane.Imie)) bledy.Add("Brak imienia");
if (dane.WzrostCm <= 0) bledy.Add("Zły wzrost");
return bledy;Lista pozwala pokazać wszystkie problemy za jednym razem.
`double.Parse` bez zabezpieczenia
double wzrost = double.Parse(PoleWzrost.Text);Wpisanie „abc” kończy się wyjątkiem FormatException i awarią programu.
double wzrost = double.TryParse(PoleWzrost.Text, out var w) ? w : 0;TryParse zwraca false zamiast rzucać wyjątek, więc możesz zareagować.
8 · Sprawdź się
Gdzie to napiszesz?
Cztery sytuacje z formularzem.
Podsumowanie
Co warto zapamiętać
- Model to klasa grupująca powiązane dane, z metodami związanymi z tymi danymi, bez wiedzy o oknie.
- Walidator to osobna klasa zwracająca listę błędów. Pusta lista oznacza poprawne dane.
- Walidator nie pokazuje komunikatów: robi to okno.
- Zbieraj wszystkie błędy naraz, a nie tylko pierwszy.
- Tekst na liczbę zamieniaj przez
TryParse, a nieParse, żeby program się nie wywrócił.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →