Lekcja 7. Kontrolki II — CheckBox, RadioButton, Switch, Slider, Pickery
ŚredniPo co się tego uczymy?
Formularze rzadko ograniczają się do wpisywania tekstu — potrzebujesz też kontrolek do zaznaczania opcji, wyboru z listy, dat i godzin. Ta lekcja dogłębnie omawia dziewięć kontrolek wyboru w .NET MAUI razem z pełnymi tabelami właściwości.
Teoria
CheckBox — zaznaczenie tak/nie
| Właściwość | Opis |
|---|---|
IsChecked |
Stan zaznaczenia — logika formularza. |
Color |
Kolor znacznika — akcent wizualny. |
IsEnabled |
Włącza/wyłącza interakcję — np. dostępny dopiero po wypełnieniu innych pól. |
RadioButton — jedna opcja z wielu
| Właściwość | Opis |
|---|---|
GroupName |
Łączy przyciski w jedną grupę — tylko jedna opcja może być zaznaczona naraz. |
Content |
Tekst/element wizualny obok "kropki" — opis opcji. |
IsChecked |
Stan zaznaczenia — do odczytu wyboru. |
Switch — przełącznik ON/OFF
| Właściwość | Opis |
|---|---|
IsToggled |
Stan włącz/wyłącz. |
OnColor |
Kolor tła w stanie ON — sygnał "aktywne". |
ThumbColor |
Kolor "gałki" przełącznika — lepsza widoczność. |
Slider — suwak wartości liczbowej
| Właściwość | Opis |
|---|---|
Minimum / Maximum |
Zakres dopuszczalnych wartości. |
Value |
Bieżąca wartość — wiążesz z modelem danych. |
MinimumTrackColor / MaximumTrackColor |
Kolory toru — jasne wskazanie postępu. |
Stepper — przycisk + / −
| Właściwość | Opis |
|---|---|
Minimum / Maximum |
Dolna/górna granica — brak wartości "poza skalą". |
Increment |
Krok zmiany wartości — decyduje o precyzji. |
Value |
Aktualna wartość. |
DatePicker i TimePicker — wybór daty i godziny
| Kontrolka | Kluczowe właściwości |
|---|---|
| DatePicker | Date (wybrana data), Format (np. dd.MM.yyyy), MinimumDate/MaximumDate — zapobiega np. wyborowi daty urodzenia z przyszłości. |
| TimePicker | Time (wybrana godzina), Format (HH:mm dla zapisu 24-godzinnego). |
Picker — lista rozwijana
| Właściwość | Opis |
|---|---|
Title |
Tekst zachęcający do wyboru, widoczny zanim użytkownik cokolwiek wybierze. |
ItemsSource |
Kolekcja danych źródłowych (w wersji "produkcyjnej" częściej niż statyczne Items). |
SelectedIndex / SelectedItem |
Pozycja albo wartość wybranego elementu. |
ItemDisplayBinding |
Która właściwość obiektu ma być wyświetlana (np. Nazwa), gdy ItemsSource to kolekcja obiektów, a nie samych tekstów. |
SearchBar — pole wyszukiwania
| Właściwość | Opis |
|---|---|
Placeholder |
Podpowiedź wyjaśniająca, co można wyszukać. |
Text |
Aktualnie wpisana fraza — wiążesz z logiką filtrowania. |
SearchButtonPressed |
Zdarzenie wywoływane po naciśnięciu Enter/ikony lupy. |
Schemat
Kiedy ktorej kontrolki uzyc: CheckBox -> zaznacz DOWOLNA liczbe opcji (0, 1, wiele) RadioButton -> wybierz DOKLADNIE JEDNA opcje z widocznej grupy Switch -> WLACZ/WYLACZ jedna opcje (jak przelacznik w telefonie) Slider -> wybierz wartosc z CIAGLEGO zakresu (np. glosnosc) Stepper -> wybierz wartosc SKOKOWO (np. liczba sztuk w koszyku) DatePicker/TimePicker -> wybierz DATE / GODZINE z kalendarza/zegara Picker -> wybierz JEDNA opcje z listy ROZWIJANEJ SearchBar -> wpisz FRAZE do wyszukania/filtrowania
Przykład z życia
Formularz rezerwacji wizyty lekarskiej w aplikacji mobilnej używa większości tych kontrolek naraz: Picker do wyboru specjalizacji lekarza, DatePicker i TimePicker do wyboru terminu, CheckBox przy "Chcę otrzymać przypomnienie SMS", i Switch przy ustawieniu "Zapamiętaj moje dane na następny raz".
AnkietaPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="KontrolkiApp2.AnkietaPage">
<ScrollView>
<VerticalStackLayout Padding="20" Spacing="16">
<Label Text="Płeć:" FontAttributes="Bold" />
<HorizontalStackLayout Spacing="15">
<RadioButton x:Name="OpcjaKobieta" Content="Kobieta" GroupName="Plec" />
<RadioButton x:Name="OpcjaMezczyzna" Content="Mężczyzna" GroupName="Plec" />
</HorizontalStackLayout>
<Label Text="Ulubiony dział informatyki:" FontAttributes="Bold" />
<Picker x:Name="ListaDzialow" Title="Wybierz dział">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Programowanie</x:String>
<x:String>Bazy danych</x:String>
<x:String>Sieci komputerowe</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Label x:Name="EtykietaOcena" Text="Poziom trudności: 5" FontAttributes="Bold" />
<Slider x:Name="SuwakOcena" Minimum="1" Maximum="10" Value="5"
ValueChanged="SuwakOcena_ValueChanged" />
<HorizontalStackLayout Spacing="10">
<CheckBox x:Name="PoleZgoda" />
<Label Text="Akceptuję regulamin ankiety" VerticalOptions="Center" />
</HorizontalStackLayout>
<Button x:Name="PrzyciskWyslij" Text="Wyślij ankietę" IsEnabled="False"
Clicked="PrzyciskWyslij_Clicked" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
AnkietaPage.xaml.cs
namespace KontrolkiApp2;
public partial class AnkietaPage : ContentPage
{
public AnkietaPage()
{
InitializeComponent();
// Przycisk wlaczy sie dopiero po zaznaczeniu zgody
PoleZgoda.CheckedChanged += (s, e) => PrzyciskWyslij.IsEnabled = e.Value;
}
private void SuwakOcena_ValueChanged(object sender, ValueChangedEventArgs e)
{
// e.NewValue to nowa wartosc suwaka (typu double)
EtykietaOcena.Text = $"Poziom trudności: {e.NewValue:F0}";
}
private async void PrzyciskWyslij_Clicked(object sender, EventArgs e)
{
string plec = OpcjaKobieta.IsChecked ? "Kobieta" : "Mężczyzna";
string dzial = ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)";
await DisplayAlert("Dziękujemy!",
$"Płeć: {plec}nDział: {dzial}nOcena trudności: {SuwakOcena.Value:F0}",
"OK");
}
}
Komentarz i wyjaśnienie kodu
Dwa RadioButton mają wspólne GroupName="Plec" — zaznaczenie jednego automatycznie odznacza drugi. Picker jest wypełniony na sztywno w XAML przez Picker.ItemsSource z tablicą x:Array — w bardziej zaawansowanych aplikacjach ta lista pochodziłaby z bazy danych i byłaby podpięta w kodzie C#.
Slider ma podpięte zdarzenie ValueChanged, które aktualizuje etykietę na bieżąco — e.NewValue jest typu double, dlatego formatujemy je jako {e.NewValue:F0}, żeby pokazać liczbę całkowitą bez miejsc po przecinku.
W konstruktorze strony podpinamy zdarzenie CheckedChanged checkboxa BEZPOŚREDNIO w C# (zamiast w XAML) — to alternatywny, równie poprawny sposób podłączenia obsługi zdarzenia, przydatny, gdy chcesz np. użyć wyrażenia lambda zamiast osobnej metody.
Ćwiczenie samodzielne
Utwórz stronę z powyższym kodem. Sprawdź: (1) czy zaznaczenie jednego RadioButtona odznacza drugi; (2) czy etykieta nad suwakiem aktualizuje się na bieżąco podczas przesuwania; (3) czy przycisk "Wyślij ankietę" jest zablokowany, dopóki nie zaznaczysz zgody.
Zadania do pracy własnej
Dodaj do ankiety trzecią opcję RadioButton 'Wolę nie podawać' do grupy Plec.
Dodaj Stepper (zakres 1-5) do wyboru 'Ile razy w tygodniu programujesz', z etykietą aktualizowaną w czasie rzeczywistym, oraz Switch 'Chcę otrzymywać powiadomienia o nowych materiałach'.
Zbuduj formularz rezerwacji wizyty: Picker z listą specjalizacji, DatePicker (z MinimumDate ustawionym na dzisiaj, żeby nie dało się wybrać przeszłej daty), TimePicker, CheckBox 'Chcę przypomnienie SMS' i SearchBar do przeszukania listy dostępnych lekarzy (na razie wystarczy, że SearchButtonPressed wypisuje wpisaną frazę w Label — pełne filtrowanie poznasz przy CollectionView).
Typowe błędy
Brak wspólnego GroupName dla RadioButton — bez tego każdy przycisk działa niezależnie i można zaznaczyć kilka naraz, co przeczy idei "wybierz jedną opcję".
Brak MinimumDate/MaximumDate przy DatePicker tam, gdzie to ma sens — formularz rezerwacji bez ograniczenia dat pozwoli użytkownikowi wybrać termin w przeszłości, co jest błędem logicznym aplikacji.
Odczyt SelectedItem bez sprawdzenia null — jeśli użytkownik nic nie wybrał w Pickerze, SelectedItem będzie null; próba użycia go bez sprawdzenia (albo operatora ?.) rzuci wyjątek.
Mylenie Value (Slider/Stepper) z typem int — obie kontrolki operują na double, więc bezpośrednie przypisanie do zmiennej typu int bez rzutowania nie skompiluje się.
Nawiązanie do egzaminu zawodowego
To dalsza realizacja INF.04.6.2 w zakresie formularzy i elementów UI. Kontrolki wyboru — CheckBox, RadioButton, Switch, Picker i pozostałe — pojawiają się w niemal każdym praktycznym zadaniu egzaminacyjnym z aplikacją mobilną, szczególnie tam, gdzie trzeba zebrać ustrukturyzowane dane od użytkownika.