Aplikacje desktopowe · Kontrolki II
CheckBox, RadioButton, ComboBox i ListBox: kontrolki wyboru
Formularze rzadko ograniczają się do samego tekstu. Użytkownik zaznacza opcje, wybiera jedną z kilku albo wskazuje element na liście. Poznasz cztery kontrolki wyboru i zbudujesz ankietę, która naprawdę działa.
- około 45 minut
- WPF · CheckBox · RadioButton · ComboBox
- INF.04.5.3
Po tej lekcji: dobrać kontrolkę do rodzaju wyboru, odczytać IsChecked, SelectedItem i SelectedIndex oraz poprawnie porównać wartość typu bool?.
Zacznijmy od sklepu
Który wybór wymaga której kontrolki?
Formularz zamówienia w sklepie internetowym używa dokładnie tego zestawu: CheckBox przy „akceptuję regulamin”, RadioButton przy formie dostawy (tylko jedna opcja), ComboBox przy wyborze kraju (dużo opcji, więc lista rozwijana oszczędza miejsce) i tabela z produktami w koszyku.
Pytanie, które zadajesz zawsze, brzmi: *ile opcji można wybrać i ile jest wszystkich?*
1 · Dobierz do potrzeby
Jedna kontrolka na jeden rodzaj wyboru
CheckBoxtak lub nie
Zaznaczenie jednej opcji. Można zaznaczyć dowolnie wiele pól naraz. Stan odczytasz z **IsChecked**.
Na przykład „Akceptuję regulamin”
RadioButtonjedna z kilku
Wybór jednej opcji z grupy. Zaznaczenie jednego odznacza pozostałe w tej samej grupie.
Na przykład kurier, paczkomat albo odbiór osobisty
ComboBoxlista rozwijana
Wybór jednej pozycji z długiej listy, przy małym zajmowanym miejscu. Wybór odczytasz z **SelectedItem lub SelectedIndex**.
Na przykład kraj, miasto, język
ListBox / DataGridlista i tabela
ListBox to lista w jednej kolumnie, DataGrid to tabela z wieloma kolumnami. W Windows Forms odpowiednikiem DataGrid jest DataGridView.
Na przykład koszyk z produktami
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
2 · Sprawdź w działaniu
Ankieta, w której wszystko jest podpięte
Zaznacz zgodę, a przycisk „Wyślij ankietę” się włączy. Przełączaj płeć i zobacz, że zaznaczenie jednej opcji odznacza drugą. Zmień język na liście i wyślij ankietę. W zakładce .cs zobaczysz, skąd biorą się te zachowania.
IsChecked ma typ bool? (może być też null), dlatego porównuj go jawnie: IsChecked == true.
3 · Pola wyboru
Właściwości CheckBox i RadioButton
| WPF | Windows Forms | Co robi |
|---|---|---|
IsChecked | Checked | Czy pole jest zaznaczone. W WPF typ bool?, więc może być też null (stan nieokreślony). |
Content | Text | Opis obok kwadracika lub kółka. |
IsThreeState (tylko CheckBox) | CheckState | Włącza trzeci, nieokreślony stan zaznaczenia. |
GroupName (tylko RadioButton) | wspólny kontener | Opcje o tej samej nazwie grupy wykluczają się wzajemnie. |
zdarzenia Checked i Unchecked | CheckedChanged | Reakcja na zmianę zaznaczenia. |
4 · Listy
Właściwości ComboBox, ListBox i DataGrid
| WPF | Windows Forms | Co robi |
|---|---|---|
ItemsSource / Items | Items / DataSource | Kolekcja elementów listy. W WPF zwykle podpina się ją z kodu lub wiązaniem. |
SelectedItem | SelectedItem | Wybrany element (jego wartość), a nie numer. |
SelectedIndex | SelectedIndex | Numer pozycji wybranego elementu, licząc od 0. Brak wyboru to −1. |
IsEditable | DropDownStyle | Czy użytkownik może wpisać własny tekst. |
SelectionMode | SelectionMode | Pojedynczy lub wielokrotny wybór (ListBox). |
AutoGenerateColumns (DataGrid) | AutoGenerateColumns | Automatyczne kolumny z właściwości obiektów w kolekcji. |
5 · Wygląd
MainWindow.xaml
Wszystkie kontrolki, które czytasz lub zmieniasz w kodzie, mają x:Name. Pole ComboBox jest puste, bo jego elementy dodamy w kodzie C#.
<Window x:Class="KontrolkiApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Ankieta" Height="360" Width="360">
<StackPanel Margin="20">
<CheckBox x:Name="PoleZgoda"
Content="Akceptuję regulamin"
Checked="PoleZgoda_Zmieniony"
Unchecked="PoleZgoda_Zmieniony" />
<TextBlock Text="Płeć:" Margin="0,15,0,5" />
<StackPanel Orientation="Horizontal">
<RadioButton x:Name="OpcjaKobieta" Content="Kobieta" GroupName="Plec" Margin="0,0,15,0" />
<RadioButton x:Name="OpcjaMezczyzna" Content="Mężczyzna" GroupName="Plec" />
</StackPanel>
<TextBlock Text="Ulubiony język programowania:" Margin="0,15,0,5" />
<ComboBox x:Name="ListaJezykow"
SelectionChanged="ListaJezykow_SelectionChanged" />
<Button x:Name="PrzyciskWyslij"
Content="Wyślij ankietę"
IsEnabled="False"
Click="PrzyciskWyslij_Click"
Margin="0,20,0,0" />
<TextBlock x:Name="EtykietaWynik" Margin="0,10,0,0" TextWrapping="Wrap" />
</StackPanel>
</Window>
CheckediUncheckedDwa zdarzenia wskazują tę samą metodę, bo w obu przypadkach trzeba odświeżyć stan przycisku.GroupName="Plec"Obie opcje należą do jednej grupy, więc zaznaczenie jednej odznacza drugą.IsEnabled="False"Przycisk „Wyślij” startuje wyłączony, aż do zaznaczenia zgody.
6 · Działanie
MainWindow.xaml.cs
Konstruktor wypełnia listę i wybiera pierwszą pozycję. Pozostałe metody reagują na zaznaczenie zgody, zmianę języka i kliknięcie przycisku.
using System.Windows;
using System.Windows.Controls;
namespace KontrolkiApp2;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ListaJezykow.Items.Add("C#");
ListaJezykow.Items.Add("Python");
ListaJezykow.Items.Add("JavaScript");
ListaJezykow.SelectedIndex = 0;
}
private void PoleZgoda_Zmieniony(object sender, RoutedEventArgs e)
{
PrzyciskWyslij.IsEnabled = PoleZgoda.IsChecked == true;
}
private void ListaJezykow_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
EtykietaWynik.Text = $"Wybrany język: {ListaJezykow.SelectedItem}";
}
private void PrzyciskWyslij_Click(object sender, RoutedEventArgs e)
{
string plec = OpcjaKobieta.IsChecked == true ? "Kobieta" : "Mężczyzna";
string jezyk = ListaJezykow.SelectedItem?.ToString() ?? "(nie wybrano)";
EtykietaWynik.Text = $"Dziękujemy! Płeć: {plec}, ulubiony język: {jezyk}.";
}
}
Items.Add("C#")Dodaje pozycję do listy. Taki zapis jest typowy, gdy lista pochodzi z bazy lub pliku.SelectedIndex = 0Zaznacza pierwszą pozycję. Bez tego lista startuje bez wyboru.IsChecked == truePorównanie ztrue, boIsCheckedjest typubool?. Zapisif (PoleZgoda.IsChecked)się nie skompiluje.SelectedItem?.ToString() ?? "(nie wybrano)"Jeśli nic nie wybrano,SelectedItemjestnull. Operator?.bezpiecznie go pomija, a??podstawia wartość zastępczą.warunek ? a : bOperator warunkowy: gdy zaznaczono „Kobieta”, wynikiem jest „Kobieta”, w przeciwnym razie „Mężczyzna”.
Do zadań
Wiele zaznaczonych pozycji oraz kolejne wiersze w DataGrid
Dwa zadania wymagają czegoś, czego nie ma w przykładzie: odczytu wielu zaznaczonych pozycji oraz tabeli, która rośnie po każdym kliknięciu.
using System.Collections.ObjectModel; // ObservableCollection
// ListBox z SelectionMode="Multiple" i pozycjami <ListBoxItem Content="Sport" />
var wybrane = new List<string>();
foreach (ListBoxItem pozycja in ListaZainteresowan.SelectedItems)
wybrane.Add(pozycja.Content.ToString()!);
Podsumowanie.Text = "Zainteresowania: " + string.Join(", ", wybrane);
// Tabela z historią odpowiedzi
public class Odpowiedz
{
public bool Zgoda { get; set; }
public string Poziom { get; set; } = "";
public string Dzial { get; set; } = "";
}
private readonly ObservableCollection<Odpowiedz> odpowiedzi = new();
public MainWindow()
{
InitializeComponent();
Historia.ItemsSource = odpowiedzi; // Historia to x:Name kontrolki DataGrid
}
private void Wyslij_Click(object sender, RoutedEventArgs e)
{
string dzial = (ComboDzial.SelectedItem as ComboBoxItem)?.Content.ToString() ?? "";
odpowiedzi.Add(new Odpowiedz { Zgoda = true, Poziom = "Średni", Dzial = dzial });
}
// Przycisk wyłączony bez zgody: wywołaj to z Checked i Unchecked pola CheckBox
PrzyciskWyslij.IsEnabled = CheckZgoda.IsChecked == true;
SelectedItemsKolekcja wszystkich zaznaczonych pozycji. Przechodzisz po niej pętląforeach.ObservableCollectionLista, która sama powiadamia tabelę o nowych elementach.Adddopisuje wiersz i nie nadpisuje poprzednich.ComboDzial.SelectedItem as ComboBoxItemPozycje wpisane w XAML są obiektamiComboBoxItem, a napis jest w ichContent.
7 · Czego unikać
Cztery pułapki kontrolek wyboru
`IsChecked` użyte wprost w warunku
if (PoleZgoda.IsChecked)
{
// ...
}Błąd kompilatora: nie można niejawnie przekonwertować typu bool? na bool.
if (PoleZgoda.IsChecked == true)
{
// ...
}bool? może mieć wartość null, więc kompilator wymaga jawnego porównania.
RadioButtony bez wspólnej grupy
<StackPanel>
<RadioButton Content="Kurier" />
</StackPanel>
<StackPanel>
<RadioButton Content="Paczkomat" />
</StackPanel>Można zaznaczyć obie opcje naraz.
<RadioButton Content="Kurier" GroupName="Dostawa" />
<RadioButton Content="Paczkomat" GroupName="Dostawa" />Opcje w różnych kontenerach działają niezależnie. Wspólny GroupName je łączy.
Pozycje ComboBoxa wpisane na sztywno
<ComboBox>
<ComboBoxItem Content="C#" />
<ComboBoxItem Content="Python" />
</ComboBox>Zadziała, ale zmiana listy wymaga zmiany plików projektu.
ListaJezykow.Items.Add("C#");
ListaJezykow.Items.Add("Python");W prawdziwych aplikacjach lista pochodzi z bazy lub pliku, więc ładuje się ją w kodzie lub przez wiązanie.
SelectedItem zamiast SelectedIndex (albo odwrotnie)
string jezyk = ListaJezykow.SelectedIndex;Błąd kompilatora: nie można przekonwertować int na string.
string jezyk = ListaJezykow.SelectedItem?.ToString();
int numer = ListaJezykow.SelectedIndex;SelectedItem zwraca element, a SelectedIndex jego numer od zera.
8 · Sprawdź się
Której kontrolki użyjesz?
Cztery sytuacje z formularzem.
Podsumowanie
Co warto zapamiętać
- CheckBox: tak lub nie, stan w
IsChecked(typbool?, porównuj z== true). - RadioButton: jedna opcja z grupy, grupę tworzy wspólny kontener lub
GroupName. - ComboBox: lista rozwijana,
SelectedItemto element, aSelectedIndexto numer od zera. - ListBox to prosta lista, a DataGrid to tabela z wieloma kolumnami.
- Zdarzenia:
CheckediUnchecked(pola wyboru),SelectionChanged(listy).
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →