Aplikacje mobilne · Kontrolki

Kontrolki II: CheckBox, RadioButton, Switch, Slider i pickery

Formularze rzadko kończą się na tekście. Potrzebujesz zaznaczania opcji, wyboru z listy, dat i godzin. Poznasz dziewięć kontrolek wyboru MAUI, zobaczysz na żywo ich właściwości i zdarzenia, a potem zbudujesz ankietę.

  • około 55 minut
  • .NET MAUI · CheckBox · Switch · Slider · Picker
  • INF.04.6.2

Po tej lekcji: dobrać kontrolkę do rodzaju wyboru, odczytać jej stan (IsChecked, IsToggled, Value, SelectedItem, Date, Time) i bezpiecznie obsłużyć brak wyboru.

Zobacz, zanim zaczniesz

Różne rodzaje wyboru

Każdy ekran to podgląd z kodu XAML. Poniżej poznasz kontrolki wyboru jedna po drugiej i każdą sprawdzisz w wyzwaniu.

Ta interakcja wymaga włączonego JavaScriptu.

Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji

Zacznij od zabawy

Stan i zdarzenia dziewięciu kontrolek

Zaznacz pole, przełącz Switch, przesuń Slider, wybierz pozycję z Pickera, wskaż datę i godzinę. Zwróć uwagę, że odznaczenie jednego RadioButtona też zgłasza zdarzenie.

Najpierw przewidź, potem sprawdź: W laboratorium zmień kolejno zgodę, suwak i Picker. Przed zmianą przewidź typ wyniku: bool, double czy wybrany obiekt. Zobacz, jak reaguje zdarzenie.

Ta interakcja wymaga włączonego JavaScriptu.

Stan odczytujesz we właściwości (IsChecked, Value…), a na zmianę reagujesz zdarzeniem (CheckedChanged, ValueChanged…). Model pomaga zobaczyć mechanizm; właściwą aplikację uruchomisz z plików poniżej.

Etap 1 z 4

CheckBox i Switch: wybór dwustanowy

CheckBox to pole, które zaznaczasz (zgoda, wybór opcji z listy). Switch to włącznik ustawienia, które działa od razu. Obie kontrolki mają dwa stany, ale inne zdarzenia: CheckedChanged i Toggled.

Wyzwanie 1 · tak/nie

Zgoda i włącznik

Ta interakcja wymaga włączonego JavaScriptu.

Sprawdź, czy zapamiętałeś

Dwa szybkie pytania

Ta interakcja wymaga włączonego JavaScriptu.

Etap 2 z 4

RadioButton: jedna odpowiedź z kilku

RadioButton służy do wyboru dokładnie jednej opcji. Aby przyciski „wiedziały”, że należą do jednej grupy, dajesz im tę samą GroupName. Bez wspólnej grupy każdy przycisk działałby osobno.

Wyzwanie 2 · cudzy kod

Dlaczego użytkownik może zaznaczyć dwie opcje?

Ta interakcja wymaga włączonego JavaScriptu.

Wyzwanie 3 · jedna grupa

Wybór rozmiaru pizzy

Ta interakcja wymaga włączonego JavaScriptu.

Sprawdź, czy zapamiętałeś

Jedno szybkie pytanie

Ta interakcja wymaga włączonego JavaScriptu.

Etap 3 z 4

Slider: wartość z zakresu

Slider ma Minimum, Maximum i Value. Wartość jest liczbą zmiennoprzecinkową (double), a zdarzenie ValueChanged podaje starą i nową wartość (e.OldValue, e.NewValue).

Wyzwanie 4 · czytanie kodu

Gdzie będzie suwak?

Ta interakcja wymaga włączonego JavaScriptu.

Wyzwanie 5 · suwak

Ocena od 1 do 5

Ta interakcja wymaga włączonego JavaScriptu.

Sprawdź, czy zapamiętałeś

Jedno szybkie pytanie

Ta interakcja wymaga włączonego JavaScriptu.

Etap 4 z 4

Picker: wybór z listy i brak wyboru

Picker to rozwijana lista. Zanim użytkownik coś wybierze, SelectedItem ma wartość null, a SelectedIndex to -1. Dlatego w obsłudze zawsze najpierw sprawdzasz, czy wybór w ogóle istnieje.

Wyzwanie 6 · logika

Ułóż obsługę Pickera

Ta interakcja wymaga włączonego JavaScriptu.

Wyzwanie końcowe

Ankieta

Ta interakcja wymaga włączonego JavaScriptu.

Sprawdź, czy zapamiętałeś

Cztery pytania z całej lekcji

Ta interakcja wymaga włączonego JavaScriptu.

2 · Dziewięć kontrolek

Właściwości i zdarzenia

KontrolkaNajważniejsze właściwościZdarzenie
CheckBoxIsChecked, Color, IsEnabledCheckedChanged (e.Value)
RadioButtonGroupName, Content, IsCheckedCheckedChanged
SwitchIsToggled, OnColor, ThumbColorToggled (e.Value)
SliderMinimum, Maximum, ValueValueChanged (e.OldValue, e.NewValue)
StepperMinimum, Maximum, Increment, ValueValueChanged
PickerItemsSource, SelectedItem, SelectedIndex, TitleSelectedIndexChanged
DatePickerDate, MinimumDate, MaximumDateDateSelected (e.NewDate)
TimePickerTimeTimeSelected (e.NewTime)
SearchBarText, PlaceholderTextChanged, SearchButtonPressed
`Slider` i `Stepper` operują na typie `double`, więc przypisanie do `int` wymaga rzutowania. Pełniejsze omówienie zdarzeń: lekcje o obsłudze zdarzeń kontrolek.

6 · Sprawdź się

Która kontrolka do jakiego wyboru?

Cztery sytuacje z formularzem.

Ta interakcja wymaga włączonego JavaScriptu.

Dla chętnych · po pierwszej stronie

Pracownia w Visual Studio: to samo w prawdziwym projekcie

Rozwiń dodatkowe warsztaty ↓

Wyzwania powyżej uczą w przeglądarce. Tu jest pełna instrukcja krok po kroku, jak zrobić to w Visual Studio i uruchomić na emulatorze, tak jak na egzaminie praktycznym. Otwórz, gdy będziesz gotowy do pracy z projektem.

1. Przygotuj miejsce pracy

Co dodajesz, a co podmieniasz?

Stronę dodaj przez Projekt → Dodaj → Nowy element → .NET MAUI ContentPage (XAML). Powstaje para .xaml i .xaml.cs. Dla ContentView wybierz szablon ContentView; dla modeli i serwisów zwykłą klasę. Jeśli plik już istnieje, podmień wskazaną zawartość — nie twórz drugiej klasy o tej samej nazwie.

PlikRola w ćwiczeniu
AnkietaPage.xamlWygląd strony lub kontrolki
AnkietaPage.xaml.csLogika i obsługa danych

Zanim uruchomisz: trzy połączenia

x:Class="MojaAplikacja.NazwaStrony" w XAML musi zgadzać się z namespace MojaAplikacja i nazwą klasy C#. InitializeComponent() tworzy kontrolki opisane w XAML.

x:Name="PoleImie" daje kodowi C# dostęp przez PoleImie.Text. Z kolei Clicked="Zapisz_Clicked" wskazuje metodę o tej nazwie w pliku .xaml.cs. Sam napis przycisku w Text niczego nie podpina.

Gdy dodajesz XAML z obsługą zdarzeń, od razu uzupełnij też odpowiadający C#. Uruchamiaj dopiero po skończeniu oznaczonej pary plików; brakujący handler nie jest błędem środowiska.

2. Uruchom sam wygląd — jeszcze bez logiki

W świeżym projekcie zastąp MainPage.xaml poniższym ekranem. W MainPage.xaml.cs zachowaj konstruktor z InitializeComponent(); usuń szablonowy licznik i OnCounterClicked, bo nie ma ich już w XAML. Na tym etapie App i AppShell pozostają z szablonu. To pełny, tymczasowy XAML — później świadomie go podmienisz, nie dokleisz do drugiego ContentPage.

MainPage.xaml — etap tymczasowyxaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MojaAplikacja.MainPage">
    <VerticalStackLayout Padding="24" Spacing="14">
        <Label Text="Moja ankieta" FontSize="24" />
        <CheckBox />
        <Slider Minimum="1" Maximum="10" Value="5" />
    </VerticalStackLayout>
</ContentPage>
  1. Pierwsza próba Uruchom. Zobaczysz kontrolki, ale przyciski bez Clicked jeszcze nic nie robią. Sprawdź rozmiar i kolejność elementów. Zatrzymaj aplikację przed następnym etapem.

3. Wskaż stronę startową ćwiczenia

Po dodaniu docelowych stron podmień App.xaml.cs na poniższy. App.xaml zostaje z szablonu. Od tej chwili startuje AnkietaPage, a nie wcześniejszy tymczasowy MainPage z AppShell. Uzupełnij jej pliki w kolejnych etapach, zanim ponownie uruchomisz projekt.

App.xaml.cscsharp
namespace MojaAplikacja;

public partial class App : Application
{
    public App() => InitializeComponent();
    protected override Window CreateWindow(IActivationState? activationState)
        => new Window(new NavigationPage(new AnkietaPage()));
}
  1. CreateWindow Tworzy okno aplikacji. NavigationPage jest kontenerem zwykłych stron i daje przycisk powrotu; nie łączymy go z Shell.
  2. new AnkietaPage() Tworzy instancję docelowej strony. Aby testować drugi niezależny przykład, zatrzymaj program, zmień tylko ten typ i uruchom ponownie.

4. Połącz wygląd z działaniem

Teraz zbuduj docelowy przykład. Pełne pliki poniżej zastępują swoje wcześniejsze wersje. Przeczytaj opis nad kodem i objaśnienia pod nim; potem sprawdź przepływ danych, nie tylko brak czerwonych podkreśleń.

Gdy przykład ma kilka plików zależnych od siebie, najpierw dodaj wszystkie wskazane typy, a potem uruchom całość. Ustaw breakpoint w obsłudze głównego przycisku i prześledź jedną próbę.

Budowa krok po kroku

AnkietaPage.xaml

Dodaj AnkietaPage. Zwróć uwagę na IsEnabled="False" przy przycisku: początkowy stan ma wynikać z wymaganej zgody.

Ankieta w ScrollView, więc zmieści się też na małym ekranie.

AnkietaPage.xamlxaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MojaAplikacja.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>
  1. RadioButton GroupName="Plec" Wspólna nazwa grupy sprawia, że zaznaczenie jednego odznacza drugi.
  2. Picker.ItemsSource z x:Array Lista pozycji zapisana w XAML. W prawdziwej aplikacji zwykle przychodzi z kodu lub bazy.
  3. Slider Minimum="1" Maximum="10" Value="5" Zakres i wartość startowa. Zdarzenie ValueChanged zgłasza każdą zmianę.
  4. Button IsEnabled="False" Przycisk włączy się dopiero po zaznaczeniu zgody.

Budowa krok po kroku

AnkietaPage.xaml.cs

Najpierw prześledź CheckedChanged i e.Value, potem ValueChanged oraz e.NewValue. Dopiero handler wysłania zbiera aktualne odpowiedzi; Picker może nie mieć wyboru.

Trzy zdarzenia: włączenie przycisku po zgodzie, aktualizacja etykiety przy ruchu suwaka i podsumowanie po kliknięciu.

AnkietaPage.xaml.cscsharp
namespace MojaAplikacja;

public partial class AnkietaPage : ContentPage
{
    public AnkietaPage()
    {
        InitializeComponent();
        // Przycisk włączy się dopiero po zaznaczeniu zgody
        PoleZgoda.CheckedChanged += (s, e) => PrzyciskWyslij.IsEnabled = e.Value;
    }

    private void SuwakOcena_ValueChanged(object sender, ValueChangedEventArgs e)
    {
        // e.NewValue to nowa wartość 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" : OpcjaMezczyzna.IsChecked ? "Mężczyzna" : "Nie podano";
        string dzial = ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)";

        await DisplayAlertAsync("Dziękujemy!",
            $"Płeć: {plec}\nDział: {dzial}\nOcena trudności: {SuwakOcena.Value:F0}",
            "OK");
    }
}
  1. PoleZgoda.CheckedChanged += (s, e) => ... Zdarzenie podpięte w konstruktorze wyrażeniem lambda. e.Value to nowy stan pola.
  2. e.NewValue:F0 Nowa wartość suwaka (typ double) sformatowana bez miejsc po przecinku.
  3. OpcjaKobieta.IsChecked ? "Kobieta" : "Mężczyzna" W MAUI IsChecked jest zwykłym bool, więc bez porównania z true (inaczej niż w WPF).
  4. ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)" Bez wyboru SelectedItem jest null. ?. i ?? chronią przed błędem.
  5. await DisplayAlertAsync(...) Okno z komunikatem. Metoda jest async, bo DisplayAlert czeka na zamknięcie okna.

5. Odbiór: czy naprawdę działa?

Wykonaj próby w swojej aplikacji, nie tylko w modelu na stronie. Zaznaczaj dopiero po sprawdzeniu wyniku. Funkcje urządzenia wymagają testu na właściwej platformie.

5 · Czego unikać

Cztery błędy z kontrolkami wyboru

RadioButtony bez wspólnego `GroupName`
Tak nie
<RadioButton Content="Kobieta" />
<RadioButton Content="Mężczyzna" />

Każdy przycisk działa niezależnie, więc można zaznaczyć oba.

Tak
<RadioButton Content="Kobieta" GroupName="Plec" />
<RadioButton Content="Mężczyzna" GroupName="Plec" />

Wspólna nazwa grupy tworzy wybór „jedna z wielu”.

DatePicker bez `MinimumDate`
Tak nie
<DatePicker />   <!-- rezerwacja wizyty -->

Można wybrać termin w przeszłości, co jest błędem logicznym aplikacji.

Tak
<DatePicker MinimumDate="{x:Static system:DateTime.Today}" />

Tam, gdzie ma to sens, ogranicz zakres dat (MinimumDate, MaximumDate).

`SelectedItem` bez sprawdzenia `null`
Tak nie
string dzial = ListaDzialow.SelectedItem.ToString();

Gdy nic nie wybrano, SelectedItem jest null i program zgłasza wyjątek.

Tak
string dzial = ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)";

?. pomija wywołanie dla null, a ?? podstawia wartość zastępczą.

`Value` suwaka przypisane do `int`
Tak nie
int poziom = SuwakOcena.Value;

Błąd kompilatora: nie można niejawnie przekonwertować double na int.

Tak
int poziom = (int)SuwakOcena.Value;

Slider i Stepper operują na double.

Ćwiczenie z pomocą · samodzielna praca

6. Mała zmiana, którą zrobisz samodzielnie

Dodaj do ankiety drugą niezależną zgodę, bez zmiany działania pierwszej.

Oczekiwany rezultat
Dodaj do ankiety drugą niezależną zgodę, bez zmiany działania pierwszej.
Dotychczasowe działanie ma pozostać poprawne.
Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź

Dodaj CheckBox z własnym x:Name i obok Label z treścią zgody.

Krok 2 — pokaż podpowiedź

Odczytaj IsChecked przy tworzeniu podsumowania.

Krok 3 — pokaż podpowiedź

Nie dawaj jej wspólnego GroupName z RadioButton — CheckBox nie tworzy wykluczającej się grupy.

Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.

Podsumowanie

Co warto zapamiętać

  1. CheckBox i Switch: tak lub nie (IsChecked, IsToggled). RadioButton: jedna z grupy (GroupName).
  2. Slider i Stepper zwracają double. Na int rzutuj.
  3. Picker: SelectedItem bywa null, więc używaj ?. i ??.
  4. DatePicker/TimePicker: Date, Time, MinimumDate, MaximumDate.
  5. Na zmianę reaguj zdarzeniem (CheckedChanged, Toggled, ValueChanged, SelectedIndexChanged, DateSelected).

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ę →
Źródła i dalsza nauka