Przechodzimy do kolejnego poziomu wtajemniczenia w budowie aplikacji desktopowych: jak sprawić, by użytkownik wprowadzał dokładnie takie dane, jakich oczekujemy, bez ryzyka literówek i chaosu?
Wiesz już, jak stworzyć pole tekstowe TextBox, ale czy dałbyś użytkownikowi wpisać w nim z klawiatury rozmiar zamawianej pizzy? Ktoś wpisze „średnia”, ktoś „32cm”, a ktoś inny „duuuża placka”. Walidacja takiego tekstu to koszmar każdego programisty.
Właśnie dlatego profesjonalne GUI korzysta z kontrolek wyboru. Dzisiaj nauczysz się, kiedy używać kwadratów (CheckBox), kiedy kółek (RadioButton) i jak elegancko zamknąć je w estetycznych ramkach (GroupBox).
1. Metafora pizzerii: Kiedy kółko, a kiedy kwadrat?
Wybór odpowiedniej kontrolki w WPF to nie kwestia gustu - to kwestia logiki biznesowej Twojej aplikacji.

Opcja A: RadioButton (Przycisk opcji) - Rozmiar pizzy
Pizzę możesz zamówić małą, średnią ALBO dużą. Nie możesz zamówić jednej pizzy, która jest jednocześnie mała i duża.
- Działa na zasadzie wzajemnego wykluczenia: zaznaczenie jednej opcji natychmiast odznacza pozostałe w grupie.
- Wizualnie to zazwyczaj kółko.
Opcja B: CheckBox (Pole wyboru) - Dodatki do pizzy
Do pizzy możesz dobrać pieczarki, podwójny ser ORAZ sos czosnkowy. Możesz też nie wybrać nic albo wybrać wszystkie możliwe pozycje.
- Działa całkowicie niezależnie - kliknięcie jednego pola nie wpływa na pozostałe.
- Wizualnie to zazwyczaj kwadrat z ptaszkiem.
2. GroupBox: Zadbaj o porządek w oknie
Rzucenie kilku luźnych przycisków na okno wygląda nieprofesjonalnie. Kontrolka GroupBox pozwala narysować elegancką, cienką ramkę z podpisem, która wizualnie grupuje powiązane ze sobą opcje.
Posiada ona dwie kluczowe właściwości:
Header: Tekst nagłówka wyświetlany w przerwaniu górnej krawędzi ramki (np.Header="Wybierz rozmiar").Content: Wnętrze ramki.
⚠️ Pamiętaj o regule pojedynczej zawartości (Single Child Rule)!
GroupBoxjest kontenerem jednoelementowym. Jeśli spróbujesz wstawić do niego bezpośrednio trzy przyciskiRadioButton, kompilator zgłosi błąd. Zawsze wkładaj do środka kontener układu - najczęściejStackPanel/DockPanel!
3. Atrybut GroupName: Tajna broń RadioButtona
Domyślnie WPF traktuje wszystkie kontrolki RadioButton znajdujące się w tym samym panelu (np. w jednym StackPanelu) jako jedną wspólną grupę.
Co jednak zrobić, gdy w formularzu masz wybór rozmiaru pizzy oraz wybór metody płatności? Jeśli nie zachowasz ostrożności, zaznaczenie płatności kartą mogłoby odznaczyć rozmiar pizzy!
Do pełnej izolacji grup służy właściwość GroupName:
<!-- Grupa 1: Rozmiar ciasta -->
<RadioButton Content="Mała (25 cm)" GroupName="RozmiarPizzy" IsChecked="True" />
<RadioButton Content="Duża (40 cm)" GroupName="RozmiarPizzy" />
<!-- Grupa 2: Płatność (działa całkowicie niezależnie!) -->
<RadioButton Content="Gotówka" GroupName="Platnosc" IsChecked="True" />
<RadioButton Content="Karta" GroupName="Platnosc" />
Dzięki podaniu GroupName masz 100% pewności, że opcje nigdy nie wejdą sobie w drogę.
4. Zobaczmy to w akcji: XAML kalkulatora zamówienia
Oto kompletny, czytelny fragment XAML, który łączy poznane kontrolki w profesjonalnie wyglądający formularz:
<StackPanel Margin="15">
<!-- SEKCJA 1: Wybór wykluczający się (RadioButton) -->
<GroupBox Header="1. Wybierz rozmiar ciasta" Margin="0,0,0,15" Padding="10">
<StackPanel>
<!-- Atrybut IsChecked="True" ustawia opcję domyślną! -->
<RadioButton x:Name="rbMala"
Content="Mała (20 zł)"
GroupName="Rozmiar"
IsChecked="True"
Margin="0,0,0,5" />
<RadioButton x:Name="rbSrednia"
Content="Średnia (30 zł)"
GroupName="Rozmiar"
Margin="0,0,0,5" />
<RadioButton x:Name="rbDuza"
Content="Duża (40 zł)"
GroupName="Rozmiar" />
</StackPanel>
</GroupBox>
<!-- SEKCJA 2: Wybór wielokrotny (CheckBox) -->
<GroupBox Header="2. Dobierz dodatki (opcjonalnie)" Margin="0,0,0,15" Padding="10">
<StackPanel>
<CheckBox x:Name="cbSer" Content="Podwójny ser (+4 zł)" Margin="0,0,0,5" />
<CheckBox x:Name="cbPieczarki" Content="Pieczarki (+3 zł)" Margin="0,0,0,5" />
<CheckBox x:Name="cbSos" Content="Sos czosnkowy (+2 zł)" />
</StackPanel>
</GroupBox>
<Button x:Name="btnPodsumuj" Content="Oblicz cenę zamówienia" Height="35" Click="btnPodsumuj_Click" />
</StackPanel>

5. Jak odczytać zaznaczenie w C#?
W kodzie C# sprawdzamy stan właściwości IsChecked.
🧠 Ważny detal techniczny:
W WPF właściwośćIsCheckedzwraca typbool?(Nullable<bool>), a nie zwykłybool. Dlatego sprawdzając warunek w instrukcjiif, zawsze dopisuj== true:
private void btnPodsumuj_Click(object sender, RoutedEventArgs e)
{
int suma = 0;
// 1. Sprawdzamy RadioButtony
if (rbMala.IsChecked == true) suma += 20;
else if (rbSrednia.IsChecked == true) suma += 30;
else if (rbDuza.IsChecked == true) suma += 40;
// 2. Sprawdzamy CheckBoxy (każdy osobno!)
if (cbSer.IsChecked == true) suma += 4;
if (cbPieczarki.IsChecked == true) suma += 3;
if (cbSos.IsChecked == true) suma += 2;
MessageBox.Show($"Łączny koszt zamówienia: {suma} zł", "Podsumowanie");
}