MessageBox — komunikaty i pytania
Czasem komunikat w napisie to za mało: przed usunięciem danych trzeba zapytać „Czy na pewno?”, a poważny błąd powinien zatrzymać użytkownika, dopóki go nie przeczyta. Do tego służy okno komunikatu MessageBox. Zadania egzaminacyjne bardzo często go wymagają. Nauczysz się dobierać ikonę i przyciski, odczytywać odpowiedź i pytać o potwierdzenie przed zamknięciem programu.
Czego się dziś nauczysz
- Wyświetlisz komunikat z tytułem, ikoną i wybranym zestawem przycisków.
- Dobierzesz ikonę do sytuacji: informacja, ostrzeżenie, błąd, pytanie.
- Odczytasz odpowiedź użytkownika (
MessageBoxResult) i uzależnisz od niej dalsze działanie. - Wyjaśnisz, co znaczy, że okno komunikatu jest modalne.
- Zapytasz o potwierdzenie przed zamknięciem okna i w razie potrzeby anulujesz zamykanie.
- Ocenisz, kiedy lepszy jest komunikat w oknie, a kiedy
MessageBox.
Komunikat, którego nie da się przeoczyć
MessageBox to małe systemowe okno z tekstem, ikoną i przyciskami. Najważniejsza cecha: jest modalne — dopóki użytkownik go nie zamknie, nie może kliknąć niczego w oknie programu, a kod czeka w miejscu wywołania. Dzięki temu można zadać pytanie i zależnie od odpowiedzi wykonać dalszą część metody.
MessageBox.Show("Zapisano zmiany."); // najprostsza wersja: tekst i przycisk OK
Status.Text = "Gotowe"; // ta linia wykona się dopiero po kliknięciu OK
MessageBox.Show z samym tekstem — bez tytułu i ikony
MessageBox jest w przestrzeni nazw System.Windows, więc nie trzeba dopisywać żadnego using.
Cztery wersje Show
Metoda MessageBox.Show ma kilka przeciążeń — każde kolejne dodaje jeden parametr:
MessageBox.Show("Tekst");
MessageBox.Show("Tekst", "Tytuł");
MessageBox.Show("Tekst", "Tytuł", MessageBoxButton.OKCancel);
MessageBox.Show("Nie wpisano nazwiska.", "Brak danych",
MessageBoxButton.OK, MessageBoxImage.Warning);
pełna wersja: tekst, tytuł, przyciski, ikona
MessageBoxButton | Przyciski |
|---|---|
OK | OK |
OKCancel | OK, Anuluj |
YesNo | Tak, Nie |
YesNoCancel | Tak, Nie, Anuluj |
MessageBoxImage | Kiedy używać |
|---|---|
Information | wszystko w porządku, informacja o wyniku |
Warning | coś wymaga uwagi, ale da się kontynuować (brak danych, mało miejsc) |
Error | operacja się nie udała (błędne dane, brak pliku) |
Question | pytanie, na które użytkownik ma odpowiedzieć |
None | bez ikony |
Napisy na przyciskach („Tak”, „Nie”, „Anuluj”) są w języku systemu Windows — nie da się ich zmienić tą metodą.
Odczyt odpowiedzi
MessageBox.Show zwraca wartość typu MessageBoxResult — informację, który przycisk kliknięto. Zapisz ją w zmiennej i sprawdź warunkiem:
private void Wyczysc_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult odpowiedz = MessageBox.Show(
"Usunąć wszystkie notatki? Tej operacji nie da się cofnąć.",
"Potwierdzenie",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (odpowiedz == MessageBoxResult.Yes)
{
Notatki.Children.Clear();
}
// przy "Nie" nic się nie dzieje
}
MessageBoxResult | Kiedy |
|---|---|
OK, Cancel | kliknięto OK / Anuluj |
Yes, No | kliknięto Tak / Nie |
Cancel przy YesNoCancel | także zamknięcie komunikatu krzyżykiem lub Esc |
Pytanie zadawaj tak, żeby „Tak” było zrozumiałe
„Usunąć wszystkie notatki?” — dobrze. „Czy nie chcesz zachować notatek?” — źle: użytkownik nie wie, czy „Tak” usuwa, czy zachowuje. Pytanie o operację nieodwracalną oznaczaj ikoną Warning.
Kiedy MessageBox, a kiedy napis w oknie
| Sytuacja | Lepiej |
|---|---|
| pytanie przed operacją, której nie da się cofnąć | MessageBox z YesNo |
| wynik obliczeń, który użytkownik chce mieć przed oczami | napis w oknie |
| błąd w formularzu z wieloma polami | napis przy formularzu (albo MessageBox, jeśli wymaga tego arkusz) |
| informacja „zapisano”, „wysłano” | krótki napis w oknie; MessageBox dopiero przy ważnych zdarzeniach |
| wymaganie z arkusza egzaminacyjnego „wyświetl okno z komunikatem” | MessageBox — dokładnie z treścią podaną w arkuszu |
Zbyt wiele okien komunikatów męczy użytkownika — po kilku zaczyna klikać OK bez czytania. Zachowaj je na sytuacje, które naprawdę wymagają uwagi.
Pytanie przy zamykaniu okna
Gdy użytkownik klika krzyżyk, okno wysyła zdarzenie Closing — zanim się zamknie. Jego parametr ma właściwość Cancel: ustawienie jej na true zatrzymuje zamykanie. Zdarzenie podpinasz w znaczniku <Window>:
<Window x:Class="Lekcja08.MainWindow"
…
Closing="Window_Closing">
// na górze pliku: using System.ComponentModel; (CancelEventArgs)
private void Window_Closing(object sender, CancelEventArgs e)
{
MessageBoxResult odpowiedz = MessageBox.Show("Zamknąć program?", "Wyjście",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (odpowiedz == MessageBoxResult.No)
{
e.Cancel = true; // okno zostaje otwarte
}
}
Okno zamkniesz też z kodu metodą Close() — np. przyciskiem Wyjście. Zdarzenie Closing wywoła się wtedy tak samo jak przy krzyżyku.
Zapisy na wycieczkę
Na wycieczkę jest 12 miejsc. Uczeń wpisuje imię i nazwisko oraz liczbę osób (1–4). Brak danych to ostrzeżenie, błędna liczba — błąd, brak miejsc — ostrzeżenie. Przed zapisaniem program pyta o potwierdzenie. Po zajęciu wszystkich miejsc pojawia się informacja. Przy próbie zamknięcia okna z zapisami na liście program pyta, czy na pewno.
po kliknięciu „Zapisz” program czeka na odpowiedź w oknie pytania
<Window x:Class="Lekcja08.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Zapisy na wycieczkę" Height="560" Width="400"
WindowStartupLocation="CenterScreen"
Closing="Window_Closing">
<StackPanel Margin="15">
<TextBlock Text="Wycieczka do Gdańska — 12 czerwca"
FontSize="18" FontWeight="Bold" TextWrapping="Wrap"/>
<TextBlock x:Name="Miejsca" Foreground="Gray" Margin="0,0,0,12"/>
<TextBlock Text="Imię i nazwisko:"/>
<TextBox x:Name="Osoba" Margin="0,2,0,8"/>
<TextBlock Text="Liczba osób (1–4):"/>
<TextBox x:Name="Liczba" Width="60" HorizontalAlignment="Left" Margin="0,2,0,10"/>
<Button Content="Zapisz" Padding="10,4" HorizontalAlignment="Left"
IsDefault="True" Click="Zapisz_Click"/>
<TextBlock Text="Lista zapisanych:" FontWeight="Bold" Margin="0,15,0,4"/>
<StackPanel x:Name="Lista"/>
</StackPanel>
</Window>
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Lekcja08;
public partial class MainWindow : Window
{
private const int LimitMiejsc = 12;
private int zajete = 0;
public MainWindow()
{
InitializeComponent();
PokazMiejsca();
}
private void Zapisz_Click(object sender, RoutedEventArgs e)
{
string osoba = Osoba.Text.Trim();
if (osoba == "")
{
MessageBox.Show("Wpisz imię i nazwisko.", "Brak danych",
MessageBoxButton.OK, MessageBoxImage.Warning);
Osoba.Focus();
return;
}
if (!int.TryParse(Liczba.Text, out int liczba) || liczba < 1 || liczba > 4)
{
MessageBox.Show("Liczba osób musi być liczbą od 1 do 4.", "Błędne dane",
MessageBoxButton.OK, MessageBoxImage.Error);
Liczba.Focus();
Liczba.SelectAll();
return;
}
if (zajete + liczba > LimitMiejsc)
{
MessageBox.Show($"Zostało tylko {LimitMiejsc - zajete} wolnych miejsc.", "Brak miejsc",
MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// Pytanie: program czeka, aż użytkownik kliknie Tak albo Nie
MessageBoxResult odpowiedz = MessageBox.Show(
$"Zapisać: {osoba} ({liczba} os.)?", "Potwierdzenie",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (odpowiedz != MessageBoxResult.Yes)
{
return;
}
zajete += liczba;
TextBlock wpis = new TextBlock();
wpis.Text = $"{Lista.Children.Count + 1}. {osoba} — {liczba} os.";
Lista.Children.Add(wpis);
Osoba.Clear();
Liczba.Clear();
PokazMiejsca();
if (zajete == LimitMiejsc)
{
MessageBox.Show("Wszystkie miejsca są już zajęte.", "Komplet",
MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private void PokazMiejsca()
{
Miejsca.Text = $"Wolne miejsca: {LimitMiejsc - zajete} z {LimitMiejsc}";
}
// Wywołuje się, gdy użytkownik próbuje zamknąć okno
private void Window_Closing(object sender, CancelEventArgs e)
{
if (Lista.Children.Count == 0)
{
return;
}
MessageBoxResult odpowiedz = MessageBox.Show(
$"Na liście jest {Lista.Children.Count} zapisów. Na pewno zamknąć program?",
"Zamykanie", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (odpowiedz == MessageBoxResult.No)
{
e.Cancel = true; // anuluje zamykanie okna
}
}
}
Co dzieje się po kolei
- Konstruktor wywołuje
PokazMiejsca(), więc napis „Wolne miejsca: 12 z 12” jest widoczny od startu. - Kliknięcie Zapisz (albo Enter —
IsDefault) sprawdza dane po kolei. Przy pierwszym problemie pojawia się komunikat z ikoną dobraną do sytuacji, kursor wraca do pola, areturnkończy metodę. - Trzecie sprawdzenie dotyczy reguły, a nie formatu danych: liczba osób jest poprawna, ale nie mieści się w wolnych miejscach.
- Pytanie o potwierdzenie zatrzymuje metodę w miejscu
MessageBox.Show. Kod idzie dalej dopiero po kliknięciu Tak albo Nie. - Przy Nie (albo zamknięciu pytania krzyżykiem) metoda się kończy — nic nie zostaje zapisane, a pola zachowują wpisane dane.
- Po zapisie nowy napis trafia do panelu
Lista, numer to liczba dotychczasowych wpisów + 1, a pola są czyszczone. Window_Closingpyta o zamknięcie tylko wtedy, gdy na liście są zapisy.e.Cancel = truezatrzymuje zamykanie. KlasaCancelEventArgswymagausing System.ComponentModel;.
Sprawdź trzy rzeczy
- Kliknij Zapisz, a gdy pojawi się pytanie, spróbuj kliknąć pole tekstowe w głównym oknie. Nie da się — komunikat jest modalny.
- Zmień
MessageBoxButton.YesNow pytaniu o zapis naOKCancel. Zapis przestanie działać — warunek sprawdzaYes, a teraz przychodziOK. - Zamknij okno przy pustej liście i przy liście z jednym zapisem. Pytanie pojawi się tylko w drugim przypadku.
Zestawienie elementów
| Element | Znaczenie | Uwagi |
|---|---|---|
MessageBox.Show(tekst, tytuł, przyciski, ikona) | okno komunikatu | Modalne — kod czeka na zamknięcie. |
MessageBoxButton | zestaw przycisków | OK, OKCancel, YesNo, YesNoCancel. |
MessageBoxImage | ikona | Information, Warning, Error, Question. |
MessageBoxResult | kliknięty przycisk | Yes, No, OK, Cancel. |
Closing | zdarzenie okna przed zamknięciem | Podpinane w znaczniku <Window>. |
CancelEventArgs e, e.Cancel = true | anulowanie zamykania | Wymaga using System.ComponentModel;. |
Close() | zamknięcie okna z kodu | Też wywołuje Closing. |
Zanim utkniesz
| Zapis lub sytuacja | Problem |
|---|---|
MessageBox.Show("Błąd", MessageBoxImage.Error); | Brak takiej wersji metody — ikona wymaga też tytułu i przycisków, w tej kolejności. |
if (MessageBox.Show(…) == "Yes") | CS0019 — wynik to MessageBoxResult, nie tekst. Porównaj z MessageBoxResult.Yes. |
przyciski OKCancel, a sprawdzane Yes | Warunek nigdy nie jest spełniony — zestaw przycisków i sprawdzana wartość muszą do siebie pasować. |
MessageBox w TextChanged | Komunikat po każdym naciśnięciu klawisza — nie da się pisać. |
Window_Closing(object sender, RoutedEventArgs e) | CS0123 — Closing wymaga parametru CancelEventArgs. |
brak using System.ComponentModel; | CS0246 — nie znaleziono CancelEventArgs. |
Close() wewnątrz Window_Closing | Okno już się zamyka — ponowne Close() w trakcie zamykania kończy się wyjątkiem InvalidOperationException. |
| polskie tytuły z literówkami, inne niż w arkuszu | Na egzaminie treść komunikatu bywa oceniana — przepisuj ją dokładnie. |
Zadania
Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
Dwa pola na liczby i przycisk Podziel. Wynik (z dwoma miejscami po przecinku) pokazuj w napisie w oknie. Błędy zgłaszaj okienkiem: brak lub błędna liczba — Error z tytułem „Błędne dane”, dzielenie przez zero — Warning z tytułem „Dzielenie przez zero” i treścią „Nie można dzielić przez 0.”. Po zamknięciu komunikatu kursor ma trafić do pola z błędem.
pokaż wskazówkę
- Kolejność: najpierw sprawdź oba pola
TryParse, potem dzielnik. Focus()wywołaj poMessageBox.Show— kod i tak poczeka na zamknięcie komunikatu.
Pole, przycisk Dodaj notatkę i lista notatek pod spodem (napisy w panelu). Przycisk Usuń wszystkie pyta: „Usunąć 5 notatek? Tej operacji nie da się cofnąć.” (z liczbą notatek) z ikoną ostrzeżenia. Przy pustej liście zamiast pytania pokaż informację „Lista jest pusta.”. Po usunięciu — informacja „Usunięto 5 notatek.”.
pokaż wskazówkę
- Liczbę notatek zapamiętaj w zmiennej przed czyszczeniem panelu — po
Clear()Countbędzie równe 0.
Okno z trzema pytaniami i polem na odpowiedź pod każdym, np. „Ile bitów ma bajt?”, „Jak nazywa się język opisu wyglądu w WPF?”, „Ile wynosi 2 do potęgi 10?”. Przycisk Sprawdź liczy poprawne odpowiedzi (wielkość liter i spacje na brzegach nie mają znaczenia) i pokazuje okienko z wynikiem „Wynik: 2/3”. Ikona: Information przy 3/3, Warning przy 1–2, Error przy 0. Potem pyta „Spróbować jeszcze raz?” — przy Tak czyści pola, przy Nie blokuje pola i przycisk.
pokaż wskazówkę
- Porównanie bez wielkości liter: zamień obie strony na małe litery (
ToLower()) poTrim(). - Ikonę wybierz do zmiennej typu
MessageBoxImage, a potem użyj jej w jednym wywołaniuShow.
Wielowierszowe pole notatki i przycisk Zapisz (na razie zapis tylko „udaje”: ustawia napis „Zapisano o 12:05”). W tytule okna pojawia się gwiazdka, gdy są niezapisane zmiany: „Notatka*”. Przy zamykaniu okna z niezapisanymi zmianami program pyta „Zapisać zmiany przed zamknięciem?” z przyciskami Tak / Nie / Anuluj: Tak — „zapisuje” i zamyka, Nie — zamyka bez zapisu, Anuluj — okno zostaje otwarte.
pokaż wskazówkę
- Pole
bool zmienionoustawiaj wTextChanged, zeruj przy zapisie. - W
Closingobsłuż trzy wynikiYesNoCancel; tylko jeden z nich ustawiae.Cancel = true.
Okno logowania do panelu biblioteki: pola Login i Kod PIN (na razie zwykłe pole tekstowe — pole na hasło poznasz w lekcji 18) oraz przycisk Zaloguj. Poprawne dane zapisz w stałych. Błędne dane: ostrzeżenie „Błędny login lub PIN. Pozostało prób: 2”, czyszczenie pola PIN i kursor w nim. Po trzeciej nieudanej próbie: błąd „Konto zablokowane. Skontaktuj się z bibliotekarzem.” i zamknięcie programu. Po udanym logowaniu: informacja „Witaj, …!” i ukrycie formularza, a pokazanie (wcześniej zwiniętego) napisu „Panel biblioteki”.
pokaż wskazówkę
- Licznik prób — pole klasy. Zamknięcie programu z kodu —
Close(). - W komunikacie nie zdradzaj, czy błędny był login, czy PIN — to dobra praktyka bezpieczeństwa.
Zbuduj kasę: rząd przycisków produktów z ceną w Tag (np. Drożdżówka 3,50 zł, Woda 2,50 zł, Kanapka 6,00 zł, Sok 4,00 zł). Kliknięcie dopisuje pozycję do paragonu (panel z napisami) i aktualizuje „Razem: 13,50 zł”. Pole „Kwota od klienta” i przycisk Zapłać:
- pusty paragon — informacja „Paragon jest pusty.”;
- błędna kwota — błąd; kwota za mała — ostrzeżenie „Brakuje 2,50 zł.”;
- poprawna — pytanie „Do zapłaty 13,50 zł. Otrzymano 20,00 zł. Reszta: 6,50 zł. Zatwierdzić?”; po Tak paragon się czyści, a licznik „Transakcji dziś: 4” rośnie.
Przycisk Anuluj paragon pyta o potwierdzenie. Przy zamykaniu programu z niepustym paragonem — ostrzeżenie z pytaniem.
pokaż wskazówkę
- Kwoty trzymaj w
decimal; ceny zTagzamieniaj przezdecimal.Parse. - Sumę paragonu trzymaj w polu klasy, zerowanym przy zapłacie i anulowaniu.
Co trzeba zapamiętać
MessageBox.Show(tekst, tytuł, przyciski, ikona)— komunikat modalny; kod czeka, aż użytkownik go zamknie.- Ikona mówi, jak poważna jest sytuacja:
Information,Warning,Error,Question. - Odpowiedź to
MessageBoxResult— porównuj ją z wartością pasującą do zestawu przycisków. - Pytaj o potwierdzenie przed operacjami nieodwracalnymi; zwykłe wyniki pokazuj w oknie.
Closing+e.Cancel = truezatrzymuje zamykanie okna;Close()zamyka okno z kodu.
Dokumentacja: Microsoft Learn — klasa MessageBox, zdarzenie Window.Closing.