TextBox i zamiana tekstu na liczby
Prawie każde zadanie egzaminacyjne z aplikacji desktopowej zaczyna się od odczytania pola, w które użytkownik coś wpisał. TextBox to takie pole. Nauczysz się odczytywać i zmieniać jego tekst, bezpiecznie zamieniać go na liczbę, reagować na błędne dane bez zamykania programu i budować pola wielowierszowe.
Czego się dziś nauczysz
- Odczytasz i zmienisz zawartość pola właściwością
Text. - Wyjaśnisz, dlaczego
"2" + "3"daje"23". - Zamienisz tekst na liczbę metodą
TryParsei obsłużysz błędne dane bez zamykania programu. - Wyjaśnisz, od czego zależy, czy separatorem dziesiętnym jest przecinek, czy kropka.
- Przeniesiesz kursor do błędnego pola metodami
Focus()iSelectAll(). - Zbudujesz pole wielowierszowe, pole tylko do odczytu i licznik znaków na żywo.
Tekst to nie liczba
W konsoli Console.ReadLine() zwracało tekst i trzeba go było zamienić na liczbę. W oknie jest dokładnie tak samo: pole oddaje zawsze tekst — nawet gdy użytkownik wpisał same cyfry.
// w polu A wpisano 2, w polu B wpisano 3
Wynik.Text = A.Text + B.Text; // "23" — to sklejenie napisów, nie dodawanie!
Różnica polega na tym, że w oknie użytkownik może kliknąć „Oblicz” w dowolnym momencie — także przy pustym polu albo z literami w polu na liczbę. Program musi to przetrwać.
Odczyt i zapis tekstu
<StackPanel Margin="15">
<TextBlock Text="Jak masz na imię?"/>
<TextBox x:Name="Imie" Margin="0,5,0,10"/>
<Button Content="Przywitaj" IsDefault="True" Click="Przywitaj_Click"/>
<TextBlock x:Name="Powitanie" Margin="0,10,0,0" FontSize="16"/>
</StackPanel>
private void Przywitaj_Click(object sender, RoutedEventArgs e)
{
string imie = Imie.Text.Trim(); // odczyt + usunięcie spacji z brzegów
if (string.IsNullOrWhiteSpace(imie))
{
Powitanie.Text = "Najpierw wpisz imię.";
return;
}
Powitanie.Text = $"Cześć, {imie}!";
Imie.Clear(); // wyczyszczenie pola
}
TextBox | TextBlock | |
|---|---|---|
| Do czego | użytkownik wpisuje dane | program wyświetla tekst |
| Ramka i kursor | tak | nie |
| Treść | Text | Text |
Trim() usuwa przypadkowe spacje z początku i końca. string.IsNullOrWhiteSpace zwraca true także dla tekstu złożonego z samych spacji — samo porównanie == "" by go przepuściło.
Parse czy TryParse?
| Metoda | Gdy tekst to „12” | Gdy tekst to „abc” albo pusty |
|---|---|---|
int.Parse(tekst) | zwraca 12 | wyjątek FormatException — program się zamyka |
int.TryParse(tekst, out int x) | zwraca true, x = 12 | zwraca false, x = 0 — program działa dalej |
private void Dodaj_Click(object sender, RoutedEventArgs e)
{
if (int.TryParse(A.Text, out int a) && int.TryParse(B.Text, out int b))
{
Wynik.Text = $"Suma: {a + b}";
}
else
{
Wynik.Text = "Wpisz dwie liczby całkowite.";
}
}
// ┌── tekst do zamiany
// │ ┌── tu trafi liczba, jeśli się udało
// ↓ ↓
// bool ok = int.TryParse(A.Text, out int a);
TryParse oddaje dwie informacje: wynik metody (bool) mówi, czy się udało, a liczbę zapisuje w zmiennej po out. Zapis out int a od razu tworzy taką zmienną. W oknie, gdzie użytkownik może wpisać cokolwiek, do odczytu pól używamy zawsze TryParse.
Liczby z przecinkiem
Dla ułamków używasz double.TryParse (przy pieniądzach — decimal.TryParse). Separator dziesiętny zależy od ustawień regionalnych Windows. Przy polskich ustawieniach:
| Wpisany tekst | Wynik double.TryParse |
|---|---|
6,5 | true, liczba 6,5 |
6.5 | false — kropka nie jest polskim separatorem dziesiętnym |
spacje przed i po 6,5 | true — spacje na brzegach są dozwolone |
| pusty | false |
Wynik w drugą stronę, z liczby na tekst, formatujesz w interpolacji: {x:F2} — dwa miejsca po przecinku, {x:F1} — jedno.
Reakcja na błędne dane
Gdy pole zawiera błąd, dobry program robi trzy rzeczy: pokazuje komunikat, przenosi kursor do złego pola i zaznacza jego treść, żeby wystarczyło zacząć pisać. Potem kończy metodę, nie licząc dalej:
if (!int.TryParse(Wiek.Text, out int wiek) || wiek < 1 || wiek > 120)
{
Komunikat.Text = "Wiek musi być liczbą od 1 do 120.";
Komunikat.Foreground = Brushes.Red;
Wiek.Focus(); // kursor wraca do pola
Wiek.SelectAll(); // cały tekst zaznaczony
return; // dalej nie liczymy
}
Dzięki || zakres sprawdza się tylko wtedy, gdy zamiana się udała. A Button IsDefault="True" z lekcji 04 pozwala zatwierdzić formularz klawiszem Enter prosto z pola.
Pole wielowierszowe, tylko do odczytu i TextChanged
<StackPanel Margin="10">
<TextBox x:Name="Notatka" Height="150"
AcceptsReturn="True"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
MaxLength="200"
TextChanged="Notatka_TextChanged"/>
<TextBlock x:Name="Licznik" Text="0 / 200" Margin="0,5,0,0"/>
</StackPanel>
// wywołuje się po KAŻDEJ zmianie tekstu: wpisaniu, usunięciu, wklejeniu, zmianie z kodu
private void Notatka_TextChanged(object sender, TextChangedEventArgs e)
{
Licznik.Text = $"{Notatka.Text.Length} / {Notatka.MaxLength}";
}
| Właściwość | Efekt |
|---|---|
AcceptsReturn="True" | Enter tworzy nową linię zamiast zatwierdzać formularz. |
TextWrapping="Wrap" | Długi tekst zawija się do następnej linii. |
VerticalScrollBarVisibility="Auto" | Pasek przewijania pojawia się, gdy tekst się nie mieści. |
MaxLength="200" | Z klawiatury nie da się wpisać więcej niż 200 znaków. 0 = bez limitu. |
IsReadOnly="True" | Tekst można zaznaczyć i skopiować, ale nie zmienić — dobre na wyniki. |
Pole w StackPanel potrzebuje wysokości
Pionowy StackPanel daje polu tyle wysokości, ile potrzebuje tekst — pusta notatka miałaby jedną linię. Dlatego pole wielowierszowe dostaje Height. Pole, które samo rośnie razem z oknem, zrobisz w lekcji 09.
Kalkulator spalania
Użytkownik wpisuje przejechany dystans, ilość paliwa i cenę litra. Program liczy spalanie na 100 km, koszt przejazdu i koszt kilometra. Każde pole jest sprawdzane osobno, a przy błędzie kursor wraca do złego pola z zaznaczonym tekstem.
Koszt przejazdu: 168,99 zł
Koszt 1 km: 0,40 zł
wynik dla poprawnych danych
<Window x:Class="Lekcja07.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Kalkulator spalania" Height="360" Width="420"
WindowStartupLocation="CenterScreen">
<StackPanel Margin="15">
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Przejechany dystans (km):" Width="180" VerticalAlignment="Center"/>
<TextBox x:Name="Dystans" Width="150" MaxLength="7"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Zużyte paliwo (l):" Width="180" VerticalAlignment="Center"/>
<TextBox x:Name="Paliwo" Width="150" MaxLength="6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Cena za litr (zł):" Width="180" VerticalAlignment="Center"/>
<TextBox x:Name="Cena" Width="150" MaxLength="5"/>
</StackPanel>
<Button Content="Oblicz" Padding="8,4" Margin="0,5,0,10"
IsDefault="True" Click="Oblicz_Click"/>
<TextBox x:Name="Wynik" Height="80"
IsReadOnly="True" TextWrapping="Wrap" FontSize="14"
Background="#FFF5F5F5"/>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Controls;
namespace Lekcja07;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Oblicz_Click(object sender, RoutedEventArgs e)
{
// 1. Zamiana tekstu na liczby — każde pole sprawdzamy osobno
if (!double.TryParse(Dystans.Text, out double dystans) || dystans <= 0)
{
PokazBlad("Dystans musi być liczbą większą od zera.", Dystans);
return;
}
if (!double.TryParse(Paliwo.Text, out double paliwo) || paliwo <= 0)
{
PokazBlad("Ilość paliwa musi być liczbą większą od zera.", Paliwo);
return;
}
if (!double.TryParse(Cena.Text, out double cena) || cena <= 0)
{
PokazBlad("Cena musi być liczbą większą od zera.", Cena);
return;
}
// 2. Obliczenia
double spalanie = paliwo / dystans * 100;
double koszt = paliwo * cena;
double kosztKm = koszt / dystans;
// 3. Wynik — liczby zamieniamy z powrotem na tekst
Wynik.Text = $"Spalanie: {spalanie:F1} l/100 km\n" +
$"Koszt przejazdu: {koszt:F2} zł\n" +
$"Koszt 1 km: {kosztKm:F2} zł";
}
// Wspólna obsługa błędu: komunikat + kursor w złym polu
private void PokazBlad(string komunikat, TextBox pole)
{
Wynik.Text = komunikat;
pole.Focus();
pole.SelectAll();
}
}
Co dzieje się po kolei
- Każdy wiersz formularza to poziomy panel: napis o stałej szerokości 180 i pole o szerokości 150 — pola tworzą równą kolumnę.
MaxLengthogranicza długość wpisu, np. dystans do 7 znaków — chroni przed przypadkowym wklejeniem długiego tekstu.IsDefault="True": po wpisaniu ceny wystarczy nacisnąć Enter.- Wynik jest w polu
TextBoxzIsReadOnly="True"— użytkownik nie zmieni wyniku, ale może go skopiować. Tło#FFF5F5F5odróżnia je od pól do wpisywania. - Każde pole sprawdza osobny
if: „to nie liczba” albo „liczba nie jest dodatnia”. Zmienna zoutjest dostępna niżej, w obliczeniach. - Przy błędzie
PokazBladwpisuje komunikat, przenosi kursor i zaznacza tekst złego pola, areturnkończy metodę — nie liczymy na złych danych (np. dzieląc przez 0). PokazBladma parametr typuTextBox, więc ta sama metoda obsługuje każde z trzech pól.- Spalanie: 27,3 l / 420 km × 100 = 6,5 l. Wszystkie zmienne to
double, więc nie ma dzielenia całkowitego. "\n"w wyniku przenosi tekst do nowej linii, a{koszt:F2}zaokrągla kwotę do groszy: 168,987 → 168,99.
Sprawdź trzy rzeczy
- Wpisz w pole paliwa
27.3(z kropką). Na polskim Windowsie pojawi się komunikat o błędzie, a tekst w polu zostanie zaznaczony. - Zamień pierwszy
double.TryParsenadouble.Parsei kliknij Oblicz przy pustym polu. Program zakończy się wyjątkiemFormatException. - Usuń
return;z bloku sprawdzającego dystans, wpisz dystans 0 i kliknij Oblicz. Komunikat o błędzie zostanie od razu zastąpiony wynikiem ze znakiem „∞” — dzielenie przez zero na typiedoublenie zamyka programu, tylko daje bezsensowny wynik.
Zestawienie elementów
| Element | Typ / zwraca | Co robi |
|---|---|---|
TextBox.Text | string | Treść pola. Puste pole to "", nigdy null. |
MaxLength | int | Limit znaków wpisywanych z klawiatury. |
IsReadOnly | bool | Blokuje edycję, pozwala kopiować. |
AcceptsReturn, TextWrapping, VerticalScrollBarVisibility | — | Razem: pole wielowierszowe z przewijaniem. |
Focus() | bool | Przenosi kursor do pola. |
SelectAll() | nic | Zaznacza cały tekst. |
Clear() | nic | Czyści pole. |
TextChanged | zdarzenie | Po każdej zmianie tekstu. Parametr TextChangedEventArgs. |
int.TryParse(s, out int x) | bool | Tekst → liczba całkowita bez ryzyka wyjątku. |
double.TryParse, decimal.TryParse | bool | Ułamki; separator według ustawień Windows. |
Trim() | string | Usuwa białe znaki z brzegów. |
string.IsNullOrWhiteSpace(s) | bool | Pusty albo same spacje. |
{x:F2} | formatowanie | Dwa miejsca po przecinku. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
int wiek = int.Parse(Wiek.Text); | Przy pustym polu FormatException i zamknięcie programu. Użyj TryParse. |
Wynik.Text = suma; | CS0029 — liczba to nie tekst. Użyj $"{suma}" albo suma.ToString(). |
if (Wiek.Text > 18) | CS0019 — nie da się porównać tekstu z liczbą. Najpierw TryParse. |
A.Text + B.Text | Sklejenie napisów: „2” + „3” = „23”. |
<TextBlock x:Name="Imie"/> jako pole do wpisywania | TextBlock tylko wyświetla. Do wpisywania potrzebny jest TextBox. |
if (Imie.Text == null) | Nigdy nie będzie prawdą — puste pole to "". |
brak return po komunikacie o błędzie | Program liczy dalej na złych danych. |
Focus() w konstruktorze okna | Okno jeszcze nie jest widoczne, fokus nie zostanie ustawiony. |
pole wielowierszowe w StackPanel bez Height | Ma wysokość jednej linii. |
Zadania
Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Komunikaty o błędach wyświetlaj w napisie w oknie. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
Kantor szkolnej wymiany: pole „Kwota w zł” i przyciski na EUR, na USD, na GBP. Kursy zapisz jako stałe (np. 4,30; 3,95; 5,10). Wynik: „250,00 zł = 58,14 EUR”. Przy pustym polu, tekście albo kwocie ujemnej pokaż czerwony komunikat i przenieś kursor do pola. Trzy przyciski obsługuje jedna metoda — kurs i symbol waluty są w Tag.
pokaż wskazówkę
- W
Tagmożesz zapisać np."4,30;EUR"i rozdzielić przezSplit(';'). Kurs zamień przezdecimal.Parse— tę wartość wpisałeś sam. - Kwotę użytkownika zamieniaj przez
decimal.TryParse.
Nauczyciel wpisuje liczbę zdobytych punktów (całkowitą) i maksymalną liczbę punktów ze sprawdzianu. Program pokazuje procent z jednym miejscem po przecinku i ocenę według progów: 0–39 % niedostateczny, 40–54 % dopuszczający, 55–69 % dostateczny, 70–84 % dobry, 85–94 % bardzo dobry, 95–100 % celujący. Odrzuć: puste pola, wartości ujemne, maksimum równe 0 i punkty większe od maksimum. W komentarzu wypisz sześć zestawów danych, którymi sprawdziłeś granice progów.
pokaż wskazówkę
- Procent licz na
double:punkty * 100.0 / maksimum— inaczej dzielenie całkowite zgubi część ułamkową. - Sprawdzaj pola po kolei i po pierwszym błędzie kończ metodę.
Okno do pisania krótkiego ogłoszenia na tablicę szkolną: wielowierszowe pole (maks. 160 znaków) i pod nim licznik „37 / 160”, aktualizowany przy każdym naciśnięciu klawisza. Gdy zostanie mniej niż 20 znaków, licznik robi się czerwony, przy mniej niż 50 — pomarańczowy. Przycisk Opublikuj przepisuje treść do napisu „Na tablicy:” pod spodem i czyści pole; przy pustym polu nic nie publikuje.
pokaż wskazówkę
- Licznik i kolor ustawiaj w
TextChanged. Pamiętaj o gałęzi przywracającej kolor czarny. - Nie ustawiaj atrybutu
Textpolu w XAML —TextChangedmógłby się wywołać, zanim powstanie licznik.
Uczeń wpisuje oceny w jednym polu, oddzielone spacjami, np. 5 4 3 6 4. Po kliknięciu Policz program pokazuje liczbę ocen, średnią z dwoma miejscami po przecinku, najwyższą i najniższą ocenę oraz informację „Średnia uprawnia do paska!”, gdy średnia wynosi co najmniej 4,75. Jeśli któryś element nie jest oceną od 1 do 6, program wypisuje dokładnie, który to element: „„7” nie jest oceną od 1 do 6”.
pokaż wskazówkę
Split(' ', StringSplitOptions.RemoveEmptyEntries)pominie puste kawałki przy podwójnych spacjach.- Najwyższą i najniższą znajdziesz w tej samej pętli, w której liczysz sumę.
Wielowierszowe pole (wysokość 200, z paskiem przewijania) i pod nim rząd przycisków: WIELKIE LITERY, małe litery, Wyczyść i Zablokuj. Ostatni przełącza pole w tryb tylko do odczytu i zmienia swój napis na Odblokuj; w trybie blokady pozostałe przyciski są nieaktywne. Pod przyciskami: „Znaków: 120, wierszy: 4”.
pokaż wskazówkę
ToUpper()iToLower()zwracają nowy napis — trzeba go przypisać z powrotem doText.- Trzy przyciski do blokowania włóż do jednego poziomego panelu z nazwą i ustawiaj jego
IsEnabled. - Wiersze policzysz przez
Split('\n').Length.
Formularz zapisu na szkolny turniej: pola Nick, Wiek, E-mail i przycisk Zarejestruj. Zasady:
- nick: 3–16 znaków, bez spacji;
- wiek: liczba całkowita od 13 do 19 (turniej dla uczniów szkół średnich);
- e-mail: dokładnie jeden znak
@, który nie jest pierwszym ani ostatnim znakiem, i co najmniej jedna kropka po@.
Przy pierwszym napotkanym błędzie pokaż czerwony komunikat, przenieś kursor do złego pola i zaznacz jego treść. Gdy wszystko jest dobrze, dodaj gracza do listy pod formularzem („3. Gracz123 (16 lat)”), wyczyść pola i ustaw kursor w polu nicku. Po zapisaniu 8 graczy wyświetl „Lista pełna” i zablokuj formularz.
pokaż wskazówkę
- Wspólna metoda błędu jak
PokazBladz przykładu oszczędzi powtarzania. IndexOf('@')zwraca pozycję pierwszego@albo −1;LastIndexOf('@')— ostatniego. Kropkę po@znajdziesz przezIndexOf('.', pozycja).- Listę zbuduj z napisów dodawanych do pustego
StackPanel(lekcja 03), a pola formularza włóż do osobnego panelu, który zablokujesz.
Co trzeba zapamiętać
TextBox.Textto zawszestring. Puste pole to"".- Do liczb używaj
TryParsei obsłuż wynikfalse;Parsena złych danych zamyka program. - Separator dziesiętny zależy od ustawień Windows — w Polsce to przecinek.
- Przy błędzie: komunikat,
Focus(),SelectAll()ireturn. AcceptsReturn+TextWrapping+VerticalScrollBarVisibility(+HeightwStackPanel) = pole wielowierszowe.IsReadOnly— tylko do odczytu, z możliwością kopiowania;TextChanged— reakcja na każdą zmianę tekstu.
Dokumentacja: Microsoft Learn — klasa TextBox, int.TryParse.