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.
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.
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
Sprawdź, czy zapamiętałeś
Dwa szybkie pytania
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?
Wyzwanie 3 · jedna grupa
Wybór rozmiaru pizzy
Sprawdź, czy zapamiętałeś
Jedno szybkie pytanie
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?
Wyzwanie 5 · suwak
Ocena od 1 do 5
Sprawdź, czy zapamiętałeś
Jedno szybkie pytanie
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
Wyzwanie końcowe
Ankieta
Sprawdź, czy zapamiętałeś
Cztery pytania z całej lekcji
2 · Dziewięć kontrolek
Właściwości i zdarzenia
| Kontrolka | Najważniejsze właściwości | Zdarzenie |
|---|---|---|
CheckBox | IsChecked, Color, IsEnabled | CheckedChanged (e.Value) |
RadioButton | GroupName, Content, IsChecked | CheckedChanged |
Switch | IsToggled, OnColor, ThumbColor | Toggled (e.Value) |
Slider | Minimum, Maximum, Value | ValueChanged (e.OldValue, e.NewValue) |
Stepper | Minimum, Maximum, Increment, Value | ValueChanged |
Picker | ItemsSource, SelectedItem, SelectedIndex, Title | SelectedIndexChanged |
DatePicker | Date, MinimumDate, MaximumDate | DateSelected (e.NewDate) |
TimePicker | Time | TimeSelected (e.NewTime) |
SearchBar | Text, Placeholder | TextChanged, SearchButtonPressed |
6 · Sprawdź się
Która kontrolka do jakiego wyboru?
Cztery sytuacje z formularzem.
Dla chętnych · po pierwszej stroniePracownia 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.
| Plik | Rola w ćwiczeniu |
|---|---|
| AnkietaPage.xaml | Wygląd strony lub kontrolki |
| AnkietaPage.xaml.cs | Logika 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.
<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>
- 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.
namespace MojaAplikacja;
public partial class App : Application
{
public App() => InitializeComponent();
protected override Window CreateWindow(IActivationState? activationState)
=> new Window(new NavigationPage(new AnkietaPage()));
}
CreateWindowTworzy okno aplikacji. NavigationPage jest kontenerem zwykłych stron i daje przycisk powrotu; nie łączymy go z Shell.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.
<?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>
RadioButton GroupName="Plec"Wspólna nazwa grupy sprawia, że zaznaczenie jednego odznacza drugi.Picker.ItemsSourcezx:ArrayLista pozycji zapisana w XAML. W prawdziwej aplikacji zwykle przychodzi z kodu lub bazy.Slider Minimum="1" Maximum="10" Value="5"Zakres i wartość startowa. ZdarzenieValueChangedzgłasza każdą zmianę.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.
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");
}
}
PoleZgoda.CheckedChanged += (s, e) => ...Zdarzenie podpięte w konstruktorze wyrażeniem lambda.e.Valueto nowy stan pola.e.NewValue:F0Nowa wartość suwaka (typdouble) sformatowana bez miejsc po przecinku.OpcjaKobieta.IsChecked ? "Kobieta" : "Mężczyzna"W MAUIIsCheckedjest zwykłymbool, więc bez porównania ztrue(inaczej niż w WPF).ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)"Bez wyboruSelectedItemjestnull.?.i??chronią przed błędem.await DisplayAlertAsync(...)Okno z komunikatem. Metoda jestasync, boDisplayAlertczeka 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`
<RadioButton Content="Kobieta" />
<RadioButton Content="Mężczyzna" />Każdy przycisk działa niezależnie, więc można zaznaczyć oba.
<RadioButton Content="Kobieta" GroupName="Plec" />
<RadioButton Content="Mężczyzna" GroupName="Plec" />Wspólna nazwa grupy tworzy wybór „jedna z wielu”.
DatePicker bez `MinimumDate`
<DatePicker /> <!-- rezerwacja wizyty -->Można wybrać termin w przeszłości, co jest błędem logicznym aplikacji.
<DatePicker MinimumDate="{x:Static system:DateTime.Today}" />Tam, gdzie ma to sens, ogranicz zakres dat (MinimumDate, MaximumDate).
`SelectedItem` bez sprawdzenia `null`
string dzial = ListaDzialow.SelectedItem.ToString();Gdy nic nie wybrano, SelectedItem jest null i program zgłasza wyjątek.
string dzial = ListaDzialow.SelectedItem?.ToString() ?? "(nie wybrano)";?. pomija wywołanie dla null, a ?? podstawia wartość zastępczą.
`Value` suwaka przypisane do `int`
int poziom = SuwakOcena.Value;Błąd kompilatora: nie można niejawnie przekonwertować double na int.
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.
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ć
CheckBoxiSwitch: tak lub nie (IsChecked,IsToggled).RadioButton: jedna z grupy (GroupName).SlideriStepperzwracajądouble. Naintrzutuj.Picker:SelectedItembywanull, więc używaj?.i??.DatePicker/TimePicker:Date,Time,MinimumDate,MaximumDate.- 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ę →