Walidacja formularza
Znasz już wszystkie podstawowe kontrolki formularza. Teraz czas połączyć je w jeden porządny formularz, który sprawdza dane tak, jak robią to prawdziwe aplikacje: pokazuje wszystkie błędy naraz, zaznacza błędne pola na czerwono, podpowiada w dymku, co jest nie tak, i przenosi kursor do pierwszego problemu. To jedna z najczęściej ocenianych umiejętności na egzaminie praktycznym.
Czego się dziś nauczysz
- Wybierzesz moment sprawdzania danych: przy zapisie, na żywo albo oba — i uzasadnisz wybór.
- Sprawdzisz typowe dane: tekst, liczbę w zakresie, datę, e-mail, numer telefonu, wybór z listy i zgody.
- Policzysz wiek na podstawie daty urodzenia.
- Zaznaczysz błędne pole czerwoną ramką i dymkiem, a potem przywrócisz jego zwykły wygląd.
- Zbierzesz wszystkie błędy w podsumowaniu i przeniesiesz kursor do pierwszego z nich.
Kiedy i jak sprawdzać
Do tej pory sprawdzałeś pola po kolei i kończyłeś metodę po pierwszym błędzie. To wystarcza w małych oknach, ale przy dłuższym formularzu użytkownik poprawia jedno pole, klika „Zapisz” i… dowiaduje się o kolejnym błędzie. Lepiej:
| Zasada | Dlaczego |
|---|---|
| sprawdź wszystkie pola naraz | użytkownik od razu widzi pełną listę poprawek |
| zaznacz błędne pola na czerwono | wzrok od razu trafia w miejsce problemu |
| komunikat mówi, co poprawić | „Numer telefonu musi mieć 9 cyfr” zamiast „Błąd w polu” |
| kursor w pierwszym błędnym polu | można od razu zacząć poprawiać |
| na żywo — dopiero po pierwszej próbie zapisu | czerwień przy pierwszym znaku pustego formularza tylko irytuje; po próbie zapisu użytkownik widzi, jak błędy znikają podczas poprawiania |
Typowe reguły
| Dane | Jak sprawdzić |
|---|---|
| tekst wymagany | string.IsNullOrWhiteSpace(pole.Text); „imię i nazwisko” — co najmniej dwa słowa po Split(' ', StringSplitOptions.RemoveEmptyEntries) |
| liczba w zakresie | int.TryParse(…, out int x) && x >= min && x <= max |
| e-mail (prosto) | dokładnie jedno @, nie na początku; po nim kropka, ale nie zaraz po @ i nie na końcu |
| telefon, kod pocztowy | usuń spacje i myślniki (Replace), sprawdź długość i char.IsDigit dla każdego znaku |
| wybór z listy | SelectedIndex != -1 |
| przyciski opcji bez wyboru domyślnego | czy któryś ma IsChecked == true |
| zgoda wymagana | IsChecked == true |
| hasła | długość, rodzaje znaków, zgodność dwóch pól (lekcja 18) |
Sprawdzanie e-maila „na sto procent” jest bardzo trudne — na egzaminie i w większości programów wystarczą proste reguły z tabeli. Ostatecznym sprawdzeniem jest i tak wysłanie wiadomości z linkiem potwierdzającym.
Data i wiek
Datę wpisaną w polu zamienisz tak jak liczbę: DateTime.TryParse. Przy polskich ustawieniach Windows rozumie zapis 12.05.2012, a odrzuca np. 31.02.2012. Wiek liczysz z różnicy lat, poprawionej o jeden, jeśli urodziny w tym roku jeszcze nie minęły:
if (!DateTime.TryParse(Data.Text, out DateTime urodziny) || urodziny > DateTime.Today)
{
// zła data albo data z przyszłości
}
else
{
int wiek = DateTime.Today.Year - urodziny.Year;
if (urodziny.AddYears(wiek) > DateTime.Today)
{
wiek--; // urodziny w tym roku jeszcze przed nami
}
}
Przykład: dziś 08.10.2026, urodziny 20.11.2010. Różnica lat to 16, ale 20.11.2026 jest po dzisiejszej dacie, więc wiek to 15. Wygodny wybór daty z kalendarza poznasz w lekcji 32.
Wyróżnianie błędów
Każda kontrolka formularza dziedziczy po klasie Control, więc ma BorderBrush (kolor ramki), Foreground i ToolTip (lekcja 05). Metoda pomocnicza z parametrem typu Control obsłuży więc pole tekstowe, listę rozwijaną i pole hasła:
private void Oznacz(Label opis, Control pole, string komunikat)
{
opis.Foreground = Brushes.Red; // czerwony opis pola
pole.BorderBrush = Brushes.Red; // czerwona ramka
pole.ToolTip = komunikat; // dymek po najechaniu myszą
}
private void OznaczOk(Label opis, Control pole)
{
opis.Foreground = Brushes.Black;
pole.ClearValue(Control.BorderBrushProperty); // przywraca domyślną ramkę
pole.ToolTip = null;
}
Dlaczego ClearValue, a nie BorderBrush = Brushes.Gray? Domyślna ramka pola ma określony odcień i zmienia kolor po najechaniu myszą i po kliknięciu. Wpisanie koloru na stałe wyłączyłoby to zachowanie. ClearValue usuwa nasze ustawienie i kontrolka wraca do wyglądu domyślnego. Nazwa Control.BorderBrushProperty oznacza „właściwość BorderBrush” — więcej o takich właściwościach w bloku o wyglądzie.
Szkielet metody Sprawdz
private string bledy = "";
private Control? pierwszyBlad = null;
private bool Sprawdz()
{
bledy = "";
pierwszyBlad = null;
if (/* pole 1 złe */) Oznacz(Opis1, Pole1, "…"); else OznaczOk(Opis1, Pole1);
if (/* pole 2 złe */) Oznacz(Opis2, Pole2, "…"); else OznaczOk(Opis2, Pole2);
// … każde pole: albo Oznacz, albo OznaczOk — nigdy return w środku
return bledy == "";
}
private void Zapisz_Click(object sender, RoutedEventArgs e)
{
if (!Sprawdz())
{
pierwszyBlad?.Focus(); // ?. — wywołaj tylko, gdy nie jest null
return;
}
// dane są poprawne — zapis
}
Najważniejsze: w Sprawdz nie ma return po pierwszym błędzie. Każde pole dostaje swoją ocenę, a Oznacz dopisuje komunikat do wspólnej listy i zapamiętuje pierwsze błędne pole. Operator ?. wywołuje metodę tylko wtedy, gdy zmienna nie jest null.
Zapisy na obóz żeglarski
Formularz zgłoszenia na obóz dla osób w wieku 10–19 lat. Po kliknięciu Zapisz program sprawdza wszystkie pola, zaznacza błędne na czerwono, wypisuje listę błędów nad formularzem i ustawia kursor w pierwszym złym polu. Od tej chwili formularz sprawdza się na żywo — błędy znikają w trakcie poprawiania. Zgoda rodzica jest wymagana tylko dla niepełnoletnich.
• Numer telefonu musi mieć 9 cyfr.
• Brak zgody rodzica na wyjazd.
po kliknięciu „Zapisz” — dwa błędy, kursor w polu telefonu
<Window x:Class="Lekcja22.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Zapisy na obóz żeglarski" SizeToContent="Height" Width="520"
ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen">
<StackPanel Margin="15">
<!-- podsumowanie błędów: ukryte, dopóki formularz jest poprawny -->
<Border x:Name="Podsumowanie" Background="#FFFDECEA" BorderBrush="IndianRed"
BorderThickness="1" CornerRadius="4" Padding="10" Margin="0,0,0,10"
Visibility="Collapsed">
<TextBlock x:Name="ListaBledow" Foreground="DarkRed" TextWrapping="Wrap"/>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label x:Name="OpisImie" Grid.Row="0" Content="_Imię i nazwisko:"
Target="{Binding ElementName=Imie}"/>
<TextBox x:Name="Imie" Grid.Row="0" Grid.Column="1" Margin="0,4"
MaxLength="50" TextChanged="Pole_Zmiana"/>
<Label x:Name="OpisData" Grid.Row="1" Content="_Data urodzenia:"
Target="{Binding ElementName=Data}"/>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<TextBox x:Name="Data" Width="100" Margin="0,4" MaxLength="10"
TextChanged="Pole_Zmiana"/>
<TextBlock Text="dd.mm.rrrr" Foreground="Gray" Margin="8,0,0,0"
VerticalAlignment="Center"/>
</StackPanel>
<Label x:Name="OpisEmail" Grid.Row="2" Content="_E-mail rodzica:"
Target="{Binding ElementName=Email}"/>
<TextBox x:Name="Email" Grid.Row="2" Grid.Column="1" Margin="0,4"
MaxLength="60" TextChanged="Pole_Zmiana"/>
<Label x:Name="OpisTelefon" Grid.Row="3" Content="_Telefon rodzica:"
Target="{Binding ElementName=Telefon}"/>
<TextBox x:Name="Telefon" Grid.Row="3" Grid.Column="1" Margin="0,4"
Width="140" HorizontalAlignment="Left" MaxLength="15"
TextChanged="Pole_Zmiana"/>
<Label x:Name="OpisTurnus" Grid.Row="4" Content="T_urnus:"
Target="{Binding ElementName=Turnus}"/>
<ComboBox x:Name="Turnus" Grid.Row="4" Grid.Column="1" Margin="0,4"
SelectionChanged="Turnus_SelectionChanged">
<ComboBoxItem Content="I turnus: 29.06–08.07"/>
<ComboBoxItem Content="II turnus: 10.07–19.07"/>
<ComboBoxItem Content="III turnus: 03.08–12.08"/>
</ComboBox>
<StackPanel Grid.Row="5" Grid.Column="1" Margin="0,6,0,0">
<CheckBox x:Name="ZgodaRodzica" Margin="0,3"
Content="Rodzic wyraża zgodę na wyjazd (wymagane dla niepełnoletnich)"
Checked="Zgoda_Zmiana" Unchecked="Zgoda_Zmiana"/>
<CheckBox x:Name="Regulamin" Content="Akceptuję regulamin obozu" Margin="0,3"
Checked="Zgoda_Zmiana" Unchecked="Zgoda_Zmiana"/>
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
<Button Content="Wy_czyść" Width="90" Height="30" Margin="0,0,8,0" Click="Wyczysc_Click"/>
<Button Content="Zapisz" Width="90" Height="30" IsDefault="True" Click="Zapisz_Click"/>
</StackPanel>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Lekcja22;
public partial class MainWindow : Window
{
private bool probowanoZapisac = false; // po pierwszej próbie sprawdzamy na żywo
private string bledy = ""; // lista komunikatów, linia po linii
private Control? pierwszyBlad = null; // tu wróci kursor
public MainWindow()
{
InitializeComponent();
}
private void Zapisz_Click(object sender, RoutedEventArgs e)
{
probowanoZapisac = true;
if (!Sprawdz())
{
pierwszyBlad?.Focus();
return;
}
MessageBox.Show($"Zapisano: {Imie.Text.Trim()}\n{Turnus.Text}\n" +
$"Potwierdzenie wyślemy na adres {Email.Text.Trim()}.",
"Zapisy", MessageBoxButton.OK, MessageBoxImage.Information);
Wyczysc();
}
private void Wyczysc_Click(object sender, RoutedEventArgs e)
{
Wyczysc();
}
// Zmiany w polach: sprawdzamy na żywo dopiero po pierwszej próbie zapisu
private void Pole_Zmiana(object sender, TextChangedEventArgs e)
{
if (probowanoZapisac) Sprawdz();
}
private void Turnus_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (probowanoZapisac) Sprawdz();
}
private void Zgoda_Zmiana(object sender, RoutedEventArgs e)
{
if (probowanoZapisac) Sprawdz();
}
// Sprawdza WSZYSTKIE pola i zaznacza błędne. Zwraca true, gdy formularz jest poprawny.
private bool Sprawdz()
{
bledy = "";
pierwszyBlad = null;
// 1. Imię i nazwisko: co najmniej dwa słowa
string imie = Imie.Text.Trim();
if (imie.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length < 2)
Oznacz(OpisImie, Imie, "Podaj imię i nazwisko uczestnika.");
else
OznaczOk(OpisImie, Imie);
// 2. Data urodzenia: poprawna data, wiek 10–19 lat w dniu dzisiejszym
int wiek = -1;
if (!DateTime.TryParse(Data.Text, out DateTime urodziny) || urodziny > DateTime.Today)
{
Oznacz(OpisData, Data, "Wpisz poprawną datę urodzenia (dd.mm.rrrr).");
}
else
{
wiek = DateTime.Today.Year - urodziny.Year;
if (urodziny.AddYears(wiek) > DateTime.Today)
{
wiek--; // urodziny w tym roku jeszcze nie minęły
}
if (wiek < 10 || wiek > 19)
Oznacz(OpisData, Data, $"Obóz jest dla osób w wieku 10–19 lat (uczestnik ma {wiek}).");
else
OznaczOk(OpisData, Data);
}
// 3. E-mail: jeden znak @, przed nim coś, po nim kropka
string email = Email.Text.Trim();
int malpa = email.IndexOf('@');
bool emailOk = malpa > 0 && malpa == email.LastIndexOf('@')
&& email.IndexOf('.', malpa) > malpa + 1 && !email.EndsWith('.');
if (!emailOk)
Oznacz(OpisEmail, Email, "Adres e-mail jest niepoprawny.");
else
OznaczOk(OpisEmail, Email);
// 4. Telefon: 9 cyfr, spacje i myślniki dozwolone
string cyfry = Telefon.Text.Replace(" ", "").Replace("-", "");
bool telefonOk = cyfry.Length == 9;
foreach (char z in cyfry)
{
if (!char.IsDigit(z)) telefonOk = false;
}
if (!telefonOk)
Oznacz(OpisTelefon, Telefon, "Numer telefonu musi mieć 9 cyfr.");
else
OznaczOk(OpisTelefon, Telefon);
// 5. Turnus
if (Turnus.SelectedIndex == -1)
Oznacz(OpisTurnus, Turnus, "Wybierz turnus.");
else
OznaczOk(OpisTurnus, Turnus);
// 6. Zgody — zgoda rodzica tylko dla niepełnoletnich
if (wiek >= 0 && wiek < 18 && ZgodaRodzica.IsChecked != true)
OznaczPole(ZgodaRodzica, "Brak zgody rodzica na wyjazd.");
else
ZgodaRodzica.Foreground = Brushes.Black;
if (Regulamin.IsChecked != true)
OznaczPole(Regulamin, "Zaakceptuj regulamin obozu.");
else
Regulamin.Foreground = Brushes.Black;
// podsumowanie nad formularzem
ListaBledow.Text = "Popraw formularz:\n" + bledy.TrimEnd();
Podsumowanie.Visibility = bledy == "" ? Visibility.Collapsed : Visibility.Visible;
return bledy == "";
}
// Zaznacza błędne pole: czerwony opis, czerwona ramka, dymek z komunikatem
private void Oznacz(Label opis, Control pole, string komunikat)
{
opis.Foreground = Brushes.Red;
pole.BorderBrush = Brushes.Red;
pole.ToolTip = komunikat;
DodajBlad(pole, komunikat);
}
private void OznaczPole(CheckBox pole, string komunikat)
{
pole.Foreground = Brushes.Red;
DodajBlad(pole, komunikat);
}
private void DodajBlad(Control pole, string komunikat)
{
bledy += "• " + komunikat + "\n";
if (pierwszyBlad == null)
{
pierwszyBlad = pole;
}
}
// Przywraca wygląd poprawnego pola
private void OznaczOk(Label opis, Control pole)
{
opis.Foreground = Brushes.Black;
pole.ClearValue(Control.BorderBrushProperty); // domyślna ramka
pole.ToolTip = null;
}
private void Wyczysc()
{
probowanoZapisac = false; // czyszczenie pól nie uruchomi sprawdzania
Imie.Clear();
Data.Clear();
Email.Clear();
Telefon.Clear();
Turnus.SelectedIndex = -1;
ZgodaRodzica.IsChecked = false;
Regulamin.IsChecked = false;
OznaczOk(OpisImie, Imie);
OznaczOk(OpisData, Data);
OznaczOk(OpisEmail, Email);
OznaczOk(OpisTelefon, Telefon);
OznaczOk(OpisTurnus, Turnus);
ZgodaRodzica.Foreground = Brushes.Black;
Regulamin.Foreground = Brushes.Black;
Podsumowanie.Visibility = Visibility.Collapsed;
Imie.Focus();
}
}
Co dzieje się po kolei
- Ramka
Podsumowanienad formularzem jest ukryta (Collapsed), dopóki są błędy do pokazania. Okno maSizeToContent="Height", więc rośnie, gdy ramka się pojawia. - Etykiety mają nazwy (
OpisImie,OpisData…) — kod zmienia ich kolor. - Pole
probowanoZapisacdecyduje, czy sprawdzać na żywo. Zdarzenia zmian (TextChanged,SelectionChanged,Checked) wywołująSprawdzdopiero po pierwszej próbie zapisu. Sprawdzocenia każde pole i wywołujeOznaczalboOznaczOk.Oznaczdopisuje komunikat dobledyi zapamiętuje pierwsze błędne pole.- Data urodzenia daje wiek — a od wieku zależy, czy wymagana jest zgoda rodzica. Gdy data jest zła,
wiekzostaje −1 i warunek zgody nie jest sprawdzany (błąd daty i tak jest na liście). - Telefon może zawierać spacje i myślniki —
Replaceusuwa je przed liczeniem cyfr. - Pola wyboru nie mają etykiety, więc
OznaczPolezmienia kolor ich własnego opisu. Wyczyscnajpierw wyłącza sprawdzanie na żywo, a dopiero potem czyści pola — inaczej każde czyszczenie zapalałoby czerwone ramki.
Sprawdź trzy rzeczy
- Kliknij Zapisz przy pustym formularzu, a potem wypełniaj pola po kolei. Komunikaty znikają z listy jeden po drugim.
- Wpisz datę urodzenia osoby 18-letniej. Błąd „Brak zgody rodzica” zniknie, choć pole zgody jest puste.
- Zamień w
OznaczOklinię zClearValuenapole.BorderBrush = Brushes.Gray;. Najedź myszą na poprawione pole — ramka przestała się podświetlać.
Zestawienie elementów
| Element | Typ | Co robi |
|---|---|---|
Control.BorderBrush | pędzel | Kolor ramki pola, listy, pola hasła. |
ToolTip | object? | Dymek po najechaniu myszą; null usuwa dymek. |
ClearValue(Control.BorderBrushProperty) | metoda | Przywraca domyślną wartość właściwości. |
DateTime.TryParse(s, out DateTime d) | bool | Tekst → data bez ryzyka wyjątku. |
DateTime.Today | DateTime | Dzisiejsza data (bez godziny). |
AddYears(n) | DateTime | Data przesunięta o n lat. |
Replace(" ", "") | string | Usuwa wszystkie spacje. |
EndsWith('.') | bool | Czy napis kończy się znakiem. |
obiekt?.Metoda() | operator | Wywołaj, gdy obiekt nie jest null. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
return po pierwszym błędzie w Sprawdz | Pozostałe pola nie są oceniane — stare czerwone ramki zostają albo nowe się nie pojawiają. |
tylko Oznacz, bez OznaczOk | Poprawione pole zostaje czerwone. |
| sprawdzanie na żywo od startu | Pusty formularz od razu świeci na czerwono. |
Wyczysc czyści pola przy włączonym sprawdzaniu na żywo | Każde czyszczenie zapala błędy. |
DateTime.Parse(Data.Text) | FormatException przy złej dacie. Użyj TryParse. |
| wiek = rok bieżący − rok urodzenia | Przez część roku wynik jest o 1 za duży. |
| komunikat „Błąd w formularzu” | Użytkownik nie wie, co poprawić. Nazwij pole i regułę. |
Zadania
Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Stosuj zasady z lekcji: wszystkie błędy naraz, czerwone wyróżnienie z dymkiem, kursor w pierwszym błędnym polu, sprawdzanie na żywo po pierwszej próbie. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
Formularz „Napisz do sekretariatu”: imię, e-mail, temat (lista: rekrutacja, legitymacja, zaświadczenie, inne), treść (wielowierszowa, 20–500 znaków, licznik pod spodem). Wyślij sprawdza wszystkie pola i pokazuje podsumowanie błędów w czerwonej ramce, a przy poprawnych danych — zieloną ramkę „Wiadomość wysłana” i czyści formularz.
pokaż wskazówkę
- Skopiuj z przykładu metody
Oznacz,OznaczOki szkieletSprawdz. - Jedna ramka może być zielona albo czerwona — zmieniasz jej
Background,BorderBrushi tekst.
Pola: ulica, numer domu, kod pocztowy, miejscowość. Kod pocztowy sprawdza się przy każdym znaku: niepełny kod ma zwykłą ramkę, poprawny NN-NNN — zieloną, a błędny (litera, zła pozycja myślnika, za długi) — czerwoną z dymkiem. Gdy użytkownik wpisze 5 cyfr bez myślnika („84300”), program sam wstawia myślnik. Przycisk Zapisz sprawdza wszystkie pola.
pokaż wskazówkę
- Po wstawieniu myślnika z kodu ustaw kursor na końcu:
CaretIndex = Text.Length. ZmianaTextwywołaTextChangeddrugi raz — upewnij się, że nie wpadniesz w pętlę.
Formularz dodawania sprzętu: numer inwentarzowy w formacie ZSMI/2026/0123 (rok 2000–bieżący, numer czterocyfrowy), nazwa, kategoria (lista), data zakupu (nie z przyszłości, a jej rok musi zgadzać się z rokiem w numerze inwentarzowym), cena (0,01–50 000 zł, z groszami), sala (lista). Poprawny sprzęt trafia do listy pod formularzem jako „ZSMI/2026/0123 — Monitor Dell (s. 204)”, a numer inwentarzowy nie może się powtórzyć.
pokaż wskazówkę
- Numer podziel
Split('/'): muszą wyjść 3 części, pierwsza to „ZSMI”, druga i trzecia — liczby o właściwej długości. - Reguła łącząca dwa pola (rok w numerze i rok zakupu) oznacza na czerwono oba pola.
Zamówienie przejazdu autokarem: nazwa grupy, liczba uczestników (1–50), liczba opiekunów, data wyjazdu (od jutra do roku naprzód), godzina wyjazdu (GG:MM, 5:00–22:00), pole wyboru Wyjazd zagraniczny. Reguły zależne: na każdych rozpoczętych 15 uczestników co najmniej jeden opiekun; przy wyjeździe zagranicznym wymagane pole Numer polisy (pojawia się dopiero po zaznaczeniu opcji). Błędy reguł zależnych pokaż przy obu polach, których dotyczą.
pokaż wskazówkę
- Godzinę sprawdzisz przez
TimeSpan.TryParsei porównanie znew TimeSpan(5, 0, 0). - Ukryte pole polisy nie powinno blokować zapisu, gdy wyjazd jest krajowy.
Biblioteka szkolna przyjmuje książki z darów. Formularz: tytuł, autor, ISBN-13 (z myślnikami lub bez), rok wydania. Numer ISBN-13 ma 13 cyfr, a ostatnia jest cyfrą kontrolną: cyfry na pozycjach nieparzystych mnożymy przez 1, na parzystych przez 3, sumujemy pierwsze 12 iloczynów, a cyfra kontrolna to (10 − suma % 10) % 10. Przy złej cyfrze kontrolnej komunikat podaje, jaka powinna być. Przykład poprawnego numeru: 978-83-246-7768-9.
pokaż wskazówkę
- Cyfrę ze znaku zamienisz przez
znak - '0'— znaki cyfr leżą w tablicy kodów po kolei. - Pozycja pierwsza to indeks 0, więc mnożnik 1 dla indeksów parzystych.
Formularz rekrutacyjny kandydata: imię, nazwisko, PESEL, data urodzenia, płeć (przyciski opcji), kierunek pierwszego i drugiego wyboru (dwie listy — nie mogą być takie same), e-mail i telefon rodzica, zgoda na przetwarzanie danych. PESEL sprawdź tak jak urzędy: 11 cyfr, poprawna cyfra kontrolna (wagi 1, 3, 7, 9, 1, 3, 7, 9, 1, 3), data urodzenia zapisana w PESEL zgodna z datą w formularzu (dla urodzonych w latach 2000–2099 do miesiąca dodaje się 20) i płeć zgodna z przedostatnią cyfrą (parzysta — kobieta). Pracuj na wymyślonych numerach PESEL, nie na prawdziwych danych.
pokaż wskazówkę
- Cyfra kontrolna:
(10 − suma % 10) % 10, gdzie suma to iloczyny pierwszych 10 cyfr przez wagi. - Rok z PESEL: dwie pierwsze cyfry; miesiąc 21–32 oznacza lata 2000. i trzeba odjąć 20.
- Reguła PESEL ↔ data ↔ płeć dotyczy trzech pól — oznacz wszystkie, których dotyczy niezgodność.
Co trzeba zapamiętać
- Sprawdzaj wszystkie pola naraz — w metodzie
Sprawdznie mareturnpo pierwszym błędzie. - Każde pole dostaje albo
Oznacz(czerwony opis, ramka, dymek), alboOznaczOk(ClearValue). - Podsumowanie błędów nad formularzem + kursor w pierwszym błędnym polu.
- Na żywo sprawdzaj dopiero po pierwszej próbie zapisu.
DateTime.TryParsedo dat; wiek liczony z poprawką na urodziny w bieżącym roku.- Komunikat mówi, co poprawić, a nie tylko, że jest błąd.
Dokumentacja: Microsoft Learn — DateTime.TryParse.