GroupBox w WPF – ramka porządkująca interfejs
Nauczysz się używać kontrolki GroupBox do logicznego grupowania elementów w oknie aplikacji. To podstawa tworzenia przejrzystych formularzy!
Co to jest GroupBox?
GroupBox to kontrolka WPF, która tworzy ramkę z nagłówkiem wokół grupy powiązanych elementów. Pomaga wizualnie i logicznie uporządkować interfejs użytkownika.
Wyobraź sobie pudełko na biurku z naklejką „Przybory do pisania”. W środku masz:
- Długopisy
- Ołówki
- Markery
GroupBox działa tak samo – tworzy „pudełko” z etykietą (nagłówkiem), w którym grupujesz powiązane kontrolki.
─────────────────
[ TextBox: Imię ]
[ TextBox: Nazwisko ]
[ TextBox: Email ]
─────────────────
○ Kobieta
○ Mężczyzna
○ Inna
↑ Dwa GroupBox-y porządkują formularz
Po co używać GroupBox?
| Zaleta | Opis |
|---|---|
| Organizacja | Grupuje powiązane elementy (np. dane adresowe, opcje płatności) |
| Czytelność | Użytkownik od razu widzi, co do czego należy |
| Logika RadioButton | RadioButtony w jednym GroupBox działają jako jedna grupa |
| Estetyka | Ramka z nagłówkiem wygląda profesjonalnie |
Podstawowa składnia XAML
GroupBox ma prostą strukturę: nagłówek (Header) i zawartość (Content).
<GroupBox Header="Dane użytkownika"> <!-- Tutaj umieszczamy kontrolki --> <StackPanel> <TextBox Text="Jan Kowalski"/> <TextBox Text="jan@email.pl"/> </StackPanel> </GroupBox>
GroupBox może zawierać tylko jeden element potomny (Content). Jeśli chcesz umieścić więcej kontrolek, musisz je „opakować” w kontener:
StackPanel– układa elementy jeden pod drugimGrid– siatka wierszy i kolumnWrapPanel– zawija elementy do nowej linii
Struktura GroupBox
„Dane osobowe”
(StackPanel/Grid)
CheckBox…
Przykład minimalny
<Window x:Class="MojaAplikacja.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="GroupBox Demo" Height="300" Width="400"> <StackPanel Margin="10"> <GroupBox Header="Informacje podstawowe" Margin="0,0,0,10"> <StackPanel Margin="10"> <Label Content="Imię:"/> <TextBox Name="txtImie"/> <Label Content="Nazwisko:"/> <TextBox Name="txtNazwisko"/> </StackPanel> </GroupBox> <Button Content="Zapisz" Width="100"/> </StackPanel> </Window>
Najważniejsze właściwości
| Właściwość | Typ | Opis | Przykład |
|---|---|---|---|
Header | object | Tekst lub kontrolka w nagłówku | Header="Opcje" |
Content | object | Zawartość GroupBox | StackPanel z kontrolkami |
BorderBrush | Brush | Kolor ramki | BorderBrush="Blue" |
BorderThickness | Thickness | Grubość ramki | BorderThickness="2" |
Padding | Thickness | Wewnętrzny margines | Padding="10" |
Margin | Thickness | Zewnętrzny margines | Margin="5" |
IsEnabled | bool | Czy aktywny | IsEnabled="False" |
Visibility | Visibility | Widoczność | Visibility="Collapsed" |
Przykład z różnymi właściwościami
<!-- Prosty GroupBox --> <GroupBox Header="Podstawowy"> <TextBlock Text="Zawartość"/> </GroupBox> <!-- Z kolorową ramką --> <GroupBox Header="Ważne informacje" BorderBrush="Red" BorderThickness="2"> <TextBlock Text="To jest ważne!"/> </GroupBox> <!-- Z większym paddingiem --> <GroupBox Header="Przestronny" Padding="20"> <TextBlock Text="Dużo miejsca wokół"/> </GroupBox> <!-- Wyłączony (wyszarzony) --> <GroupBox Header="Niedostępne opcje" IsEnabled="False"> <CheckBox Content="Ta opcja jest wyłączona"/> </GroupBox>
Właściwość Header przyjmuje dowolny obiekt. Możesz tam umieścić np. StackPanel z ikoną i tekstem:
<GroupBox> <GroupBox.Header> <StackPanel Orientation="Horizontal"> <TextBlock Text="⚙️" FontSize="16" Margin="0,0,5,0"/> <TextBlock Text="Ustawienia" FontWeight="Bold"/> </StackPanel> </GroupBox.Header> <StackPanel> <CheckBox Content="Opcja 1"/> <CheckBox Content="Opcja 2"/> </StackPanel> </GroupBox>
Grupowanie RadioButton – najważniejsze zastosowanie
GroupBox jest idealny do grupowania RadioButton. Wszystkie RadioButtony w jednym GroupBox działają jako jedna grupa – można wybrać tylko jedną opcję.
RadioButtony automatycznie „wiedzą”, że są w jednej grupie, gdy mają wspólnego rodzica (np. ten sam StackPanel wewnątrz GroupBox). Wybranie jednego RadioButton automatycznie odznacza pozostałe.
<StackPanel Margin="10"> <!-- GRUPA 1: Rozmiar --> <GroupBox Header="Wybierz rozmiar" Margin="0,0,0,10"> <StackPanel> <RadioButton Content="Mały" Name="rbMaly"/> <RadioButton Content="Średni" Name="rbSredni" IsChecked="True"/> <RadioButton Content="Duży" Name="rbDuzy"/> </StackPanel> </GroupBox> <!-- GRUPA 2: Kolor (niezależna od grupy rozmiaru!) --> <GroupBox Header="Wybierz kolor" Margin="0,0,0,10"> <StackPanel> <RadioButton Content="Czerwony" Name="rbCzerwony"/> <RadioButton Content="Zielony" Name="rbZielony"/> <RadioButton Content="Niebieski" Name="rbNiebieski" IsChecked="True"/> </StackPanel> </GroupBox> <Button Content="Zatwierdź wybór" Click="Button_Click"/> </StackPanel>
● Średni ← wybrano
○ Duży
○ Zielony
● Niebieski ← wybrano
↑ Dwie niezależne grupy – możesz wybrać Średni rozmiar I Niebieski kolor
Obsługa w kodzie C#
private void Button_Click(object sender, RoutedEventArgs e) { // Sprawdzamy rozmiar string rozmiar = ""; if (rbMaly.IsChecked == true) rozmiar = "Mały"; else if (rbSredni.IsChecked == true) rozmiar = "Średni"; else if (rbDuzy.IsChecked == true) rozmiar = "Duży"; // Sprawdzamy kolor string kolor = ""; if (rbCzerwony.IsChecked == true) kolor = "Czerwony"; else if (rbZielony.IsChecked == true) kolor = "Zielony"; else if (rbNiebieski.IsChecked == true) kolor = "Niebieski"; MessageBox.Show($"Wybrałeś: {rozmiar}, {kolor}"); }
IsChecked jest typu bool? (nullable bool) – może być true, false lub null. Dlatego porównujemy explicite z true.
Grupowanie CheckBox
CheckBox-y też często grupujemy w GroupBox – dla czytelności. W przeciwieństwie do RadioButton, można zaznaczyć wiele CheckBox-ów naraz.
<GroupBox Header="Wybierz dodatki do pizzy" Margin="10"> <StackPanel> <CheckBox Content="Ser" Name="chkSer" IsChecked="True"/> <CheckBox Content="Szynka" Name="chkSzynka"/> <CheckBox Content="Pieczarki" Name="chkPieczarki"/> <CheckBox Content="Oliwki" Name="chkOliwki"/> <CheckBox Content="Pepperoni" Name="chkPepperoni"/> </StackPanel> </GroupBox> <Button Content="Zamów" Click="Zamow_Click"/>
private void Zamow_Click(object sender, RoutedEventArgs e) { List<string> dodatki = new List<string>(); if (chkSer.IsChecked == true) dodatki.Add("Ser"); if (chkSzynka.IsChecked == true) dodatki.Add("Szynka"); if (chkPieczarki.IsChecked == true) dodatki.Add("Pieczarki"); if (chkOliwki.IsChecked == true) dodatki.Add("Oliwki"); if (chkPepperoni.IsChecked == true) dodatki.Add("Pepperoni"); string lista = string.Join(", ", dodatki); MessageBox.Show($"Twoja pizza z: {lista}"); }
RadioButton
Można wybrać tylko jedną opcję z grupy
- ○ Opcja A
- ● Opcja B ← wybrana
- ○ Opcja C
Użyj gdy: rozmiar, płeć, metoda płatności
CheckBox
Można wybrać dowolną liczbę opcji
- ☑ Opcja A ← wybrana
- ☐ Opcja B
- ☑ Opcja C ← wybrana
Użyj gdy: dodatki, zainteresowania, zgody
Zagnieżdżanie kontrolek w GroupBox
W GroupBox możesz umieścić dowolne kontrolki – TextBox, ComboBox, DatePicker, a nawet inne GroupBox-y!
Formularz z różnymi kontrolkami
<StackPanel Margin="10"> <!-- DANE OSOBOWE --> <GroupBox Header="Dane osobowe" Margin="0,0,0,10"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="30"/> <RowDefinition Height="30"/> </Grid.RowDefinitions> <Label Content="Imię:" Grid.Row="0"/> <TextBox Name="txtImie" Grid.Row="0" Grid.Column="1"/> <Label Content="Nazwisko:" Grid.Row="1"/> <TextBox Name="txtNazwisko" Grid.Row="1" Grid.Column="1"/> <Label Content="Data ur.:" Grid.Row="2"/> <DatePicker Name="dpDataUrodzenia" Grid.Row="2" Grid.Column="1"/> </Grid> </GroupBox> <!-- ADRES --> <GroupBox Header="Adres zamieszkania" Margin="0,0,0,10"> <StackPanel> <TextBox Name="txtUlica" Margin="0,5"/> <StackPanel Orientation="Horizontal"> <TextBox Name="txtKodPocztowy" Width="80" Margin="0,0,10,0"/> <TextBox Name="txtMiasto" Width="150"/> </StackPanel> </StackPanel> </GroupBox> <!-- PREFERENCJE --> <GroupBox Header="Preferencje"> <StackPanel> <CheckBox Content="Newsletter"/> <CheckBox Content="Powiadomienia SMS"/> <ComboBox Margin="0,10,0,0"> <ComboBoxItem Content="Polski" IsSelected="True"/> <ComboBoxItem Content="English"/> <ComboBoxItem Content="Deutsch"/> </ComboBox> </StackPanel> </GroupBox> </StackPanel>
Zagnieżdżone GroupBox-y (GroupBox w GroupBox)
<GroupBox Header="Ustawienia programu" Padding="10"> <StackPanel> <!-- Zagnieżdżony GroupBox 1 --> <GroupBox Header="Wygląd" Margin="0,0,0,10"> <StackPanel> <RadioButton Content="Jasny motyw"/> <RadioButton Content="Ciemny motyw" IsChecked="True"/> </StackPanel> </GroupBox> <!-- Zagnieżdżony GroupBox 2 --> <GroupBox Header="Dźwięk"> <StackPanel> <CheckBox Content="Włącz dźwięki" IsChecked="True"/> <Slider Minimum="0" Maximum="100" Value="75"/> </StackPanel> </GroupBox> </StackPanel> </GroupBox>
Stylowanie GroupBox
Możesz dostosować wygląd GroupBox-a za pomocą właściwości lub stylów.
Podstawowe stylowanie
<!-- Kolorowa ramka --> <GroupBox Header="Ważne" BorderBrush="#E74C3C" BorderThickness="2" Padding="15"> <TextBlock Text="Uwaga!"/> </GroupBox> <!-- Z tłem --> <GroupBox Header="Podświetlony" Background="#F0F8FF" Padding="10"> <TextBlock Text="Jasne tło"/> </GroupBox> <!-- Stylizowany nagłówek --> <GroupBox Padding="10"> <GroupBox.Header> <TextBlock Text="★ Premium" FontWeight="Bold" Foreground="Gold" FontSize="14"/> </GroupBox.Header> <TextBlock Text="Funkcje premium"/> </GroupBox>
Styl w zasobach (reużywalny)
<Window.Resources> <!-- Definicja stylu --> <Style x:Key="StylWazny" TargetType="GroupBox"> <Setter Property="BorderBrush" Value="#3498DB"/> <Setter Property="BorderThickness" Value="2"/> <Setter Property="Padding" Value="10"/> <Setter Property="Margin" Value="5"/> <Setter Property="FontWeight" Value="SemiBold"/> </Style> </Window.Resources> <StackPanel> <!-- Użycie stylu --> <GroupBox Header="Pierwszy" Style="{StaticResource StylWazny}"> <TextBlock Text="Zawartość"/> </GroupBox> <GroupBox Header="Drugi" Style="{StaticResource StylWazny}"> <TextBlock Text="Inna zawartość"/> </GroupBox> </StackPanel>
Obsługa GroupBox w kodzie C#
Możesz dynamicznie zmieniać właściwości GroupBox z poziomu kodu C#.
Zmiana właściwości
<GroupBox Name="grpOpcje" Header="Opcje"> <StackPanel> <CheckBox Content="Opcja 1"/> <CheckBox Content="Opcja 2"/> </StackPanel> </GroupBox> <Button Content="Włącz/Wyłącz" Click="Toggle_Click"/> <Button Content="Zmień nagłówek" Click="ZmienHeader_Click"/> <Button Content="Pokaż/Ukryj" Click="Visibility_Click"/>
// Włącz/Wyłącz GroupBox (i wszystkie kontrolki wewnątrz) private void Toggle_Click(object sender, RoutedEventArgs e) { grpOpcje.IsEnabled = !grpOpcje.IsEnabled; } // Zmień tekst nagłówka private void ZmienHeader_Click(object sender, RoutedEventArgs e) { grpOpcje.Header = "Nowy nagłówek"; } // Pokaż/Ukryj GroupBox private void Visibility_Click(object sender, RoutedEventArgs e) { if (grpOpcje.Visibility == Visibility.Visible) grpOpcje.Visibility = Visibility.Collapsed; else grpOpcje.Visibility = Visibility.Visible; }
Dynamiczne tworzenie GroupBox
private void UtworzGroupBox() { // Tworzenie GroupBox GroupBox nowyGroupBox = new GroupBox(); nowyGroupBox.Header = "Utworzony dynamicznie"; nowyGroupBox.Margin = new Thickness(10); // Tworzenie zawartości StackPanel panel = new StackPanel(); panel.Children.Add(new CheckBox { Content = "Opcja A" }); panel.Children.Add(new CheckBox { Content = "Opcja B" }); panel.Children.Add(new CheckBox { Content = "Opcja C" }); // Przypisanie zawartości nowyGroupBox.Content = panel; // Dodanie do okna (zakładając że mamy StackPanel o nazwie "mainPanel") mainPanel.Children.Add(nowyGroupBox); }
Praktyczne przykłady
Przykład 1: Formularz rejestracji
<Window Title="Rejestracja" Height="500" Width="400"> <StackPanel Margin="15"> <!-- DANE KONTA --> <GroupBox Header="Dane konta" Margin="0,0,0,10"> <StackPanel Margin="10"> <Label Content="Email:"/> <TextBox Name="txtEmail"/> <Label Content="Hasło:" Margin="0,10,0,0"/> <PasswordBox Name="txtHaslo"/> <Label Content="Powtórz hasło:" Margin="0,10,0,0"/> <PasswordBox Name="txtHaslo2"/> </StackPanel> </GroupBox> <!-- TYP KONTA --> <GroupBox Header="Typ konta" Margin="0,0,0,10"> <StackPanel Margin="10"> <RadioButton Content="Konto prywatne" IsChecked="True"/> <RadioButton Content="Konto firmowe"/> <RadioButton Content="Konto studenckie"/> </StackPanel> </GroupBox> <!-- ZGODY --> <GroupBox Header="Zgody i regulamin" Margin="0,0,0,10"> <StackPanel Margin="10"> <CheckBox Content="Akceptuję regulamin" Name="chkRegulamin"/> <CheckBox Content="Zgoda na newsletter"/> <CheckBox Content="Zgoda na marketing"/> </StackPanel> </GroupBox> <Button Content="Zarejestruj się" Height="35" Click="Rejestruj_Click"/> </StackPanel> </Window>
Przykład 2: Konfiguracja zamówienia
<Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- Lewa kolumna --> <StackPanel Grid.Column="0" Margin="0,0,5,0"> <GroupBox Header="Rozmiar pizzy" Margin="0,0,0,10"> <StackPanel Margin="10"> <RadioButton Content="Mała (25cm) - 20 zł"/> <RadioButton Content="Średnia (32cm) - 28 zł" IsChecked="True"/> <RadioButton Content="Duża (45cm) - 38 zł"/> </StackPanel> </GroupBox> <GroupBox Header="Rodzaj ciasta"> <StackPanel Margin="10"> <RadioButton Content="Cienkie" IsChecked="True"/> <RadioButton Content="Grube"/> <RadioButton Content="Z serem w brzegach (+5 zł)"/> </StackPanel> </GroupBox> </StackPanel> <!-- Prawa kolumna --> <GroupBox Header="Dodatki (+3 zł każdy)" Grid.Column="1" Margin="5,0,0,0"> <StackPanel Margin="10"> <CheckBox Content="Podwójny ser"/> <CheckBox Content="Szynka"/> <CheckBox Content="Pieczarki"/> <CheckBox Content="Oliwki"/> <CheckBox Content="Papryka"/> <CheckBox Content="Kukurydza"/> <CheckBox Content="Jalapeño"/> </StackPanel> </GroupBox> </Grid>
Częste błędy
❌ Błąd 1: Wiele elementów bezpośrednio w GroupBox
❌ Źle
<GroupBox Header="Test">
<TextBox/>
<TextBox/> <!-- BŁĄD! -->
</GroupBox>
GroupBox może mieć tylko jeden element potomny!
✅ Dobrze
<GroupBox Header="Test">
<StackPanel>
<TextBox/>
<TextBox/>
</StackPanel>
</GroupBox>
Opakuj w kontener (StackPanel, Grid…)
❌ Błąd 2: RadioButtony w różnych kontenerach
❌ Źle
<GroupBox Header="Wybór">
<Grid>
<StackPanel>
<RadioButton Content="A"/>
</StackPanel>
<StackPanel>
<RadioButton Content="B"/>
</StackPanel>
</Grid>
</GroupBox>
RadioButtony w różnych StackPanel-ach to różne grupy!
✅ Dobrze
<GroupBox Header="Wybór">
<StackPanel>
<RadioButton Content="A"/>
<RadioButton Content="B"/>
</StackPanel>
</GroupBox>
Wspólny kontener = jedna grupa
❌ Błąd 3: Brak Name dla kontrolek
❌ Źle
<RadioButton Content="Tak"/> <RadioButton Content="Nie"/>
Jak sprawdzisz w C#, która opcja jest wybrana?
✅ Dobrze
<RadioButton Name="rbTak" Content="Tak"/> <RadioButton Name="rbNie" Content="Nie"/>
Teraz możesz użyć: rbTak.IsChecked
❌ Błąd 4: Zapominanie o IsChecked == true
❌ Źle
if (rbTak.IsChecked) // Błąd!
IsChecked to bool?, nie bool
✅ Dobrze
if (rbTak.IsChecked == true)
Porównaj explicite z true
Podsumowanie
- GroupBox = ramka z nagłówkiem do grupowania kontrolek
- Header = tekst (lub dowolna kontrolka) w nagłówku
- Content = może być tylko JEDEN element (użyj StackPanel/Grid)
- RadioButton w jednym GroupBox = jedna grupa (tylko 1 wybór)
- CheckBox w GroupBox = dla czytelności (wiele wyborów)
- Można zagnieżdżać GroupBox w GroupBox
- Można stylować – BorderBrush, Padding, Background
Tabela szybkiego przypomnienia
| Co chcesz zrobić? | Jak to zrobić? |
|---|---|
| Utworzyć ramkę z tytułem | <GroupBox Header="Tytuł"> |
| Dodać wiele kontrolek | Opakuj w <StackPanel> |
| Jedna opcja z wielu | RadioButton w GroupBox |
| Wiele opcji naraz | CheckBox w GroupBox |
| Zmienić kolor ramki | BorderBrush="Red" |
| Wyłączyć sekcję | IsEnabled="False" |
| Ukryć sekcję | Visibility="Collapsed" |
Zadania praktyczne
📝 Zadanie 1: Formularz ankiety
Utwórz formularz ankiety z trzema GroupBox-ami:
- Dane respondenta: imię (TextBox), wiek (ComboBox: 18-25, 26-35, 36-50, 50+)
- Ocena produktu: RadioButtony (1-5 gwiazdek)
- Co Ci się podobało: CheckBoxy (Cena, Jakość, Design, Obsługa klienta)
Dodaj przycisk „Wyślij” z obsługą Click, która wyświetli podsumowanie w MessageBox.
💡 Podpowiedź: Dla ComboBox użyj SelectedItem lub SelectedIndex
📝 Zadanie 2: Konfigurator komputera
Utwórz aplikację konfiguratora PC z GroupBox-ami:
- Procesor: RadioButtony (Intel i5, Intel i7, AMD Ryzen 5, AMD Ryzen 7)
- RAM: RadioButtony (8GB, 16GB, 32GB, 64GB)
- Dysk: RadioButtony (256GB SSD, 512GB SSD, 1TB SSD, 1TB HDD)
- Dodatkowe opcje: CheckBoxy (Karta graficzna, WiFi 6, Bluetooth)
Przycisk „Podsumuj konfigurację” ma pokazać wybrane komponenty.
💡 Podpowiedź: Możesz ułożyć GroupBox-y w Grid z 2 kolumnami
📝 Zadanie 3: Ustawienia aplikacji
Stwórz okno ustawień z zagnieżdżonymi GroupBox-ami:
- Główny GroupBox „Ustawienia” zawiera:
- GroupBox „Wygląd” – RadioButton: Jasny/Ciemny motyw
- GroupBox „Język” – ComboBox z językami
- GroupBox „Powiadomienia” – CheckBoxy: Email, SMS, Push
Dodaj przyciski „Zapisz” i „Anuluj”.
💡 Podpowiedź: Użyj Padding w głównym GroupBox, żeby było miejsce na zagnieżdżone
⭐ Zadanie 4: Dynamiczne włączanie sekcji
Utwórz formularz zamówienia gdzie:
- CheckBox „Dostawa pod adres” – gdy zaznaczony, włącza GroupBox z polami adresu
- CheckBox „Faktura VAT” – gdy zaznaczony, włącza GroupBox z danymi firmy
Użyj zdarzenia Checked i Unchecked CheckBox-a do zmiany IsEnabled GroupBox-ów.
💡 Podpowiedź: grpAdres.IsEnabled = chkDostawa.IsChecked == true;
⭐⭐ Zadanie 5: Kalkulator ceny
Rozbuduj konfigurator pizzy z przykładu:
- Dodaj ceny do każdej opcji
- Na bieżąco obliczaj i wyświetlaj sumę w TextBlock
- Użyj zdarzeń
CheckedRadioButton i CheckBox
Suma powinna się aktualizować przy każdej zmianie wyboru.
💡 Podpowiedź: Utwórz metodę ObliczCene() wywoływaną przez wszystkie zdarzenia Checked