Przejdź do treści
School IT / Przestrzeń do nauki

Slider — suwak

Głośność, jasność, rozmiar czcionki, temperatura — gdy liczba ma leżeć w znanym zakresie, wygodniej przesunąć suwak niż ją wpisywać. Suwak sam pilnuje zakresu, więc nie trzeba sprawdzać danych tak jak w polu tekstowym. Nauczysz się ustawiać zakres i krok, dodawać podziałkę i reagować na przesuwanie na żywo.

XAML C# Slider Minimum / Maximum ValueChanged IsSnapToTickEnabled 90 min
CEL LEKCJI

Czego się dziś nauczysz

  • Dodasz suwak z zakresem Minimum–Maximum i wartością początkową.
  • Ustawisz krok, o jaki zmienia się wartość, i pokażesz podziałkę.
  • Zareagujesz na przesuwanie zdarzeniem ValueChanged i zabezpieczysz je na starcie okna.
  • Wyświetlisz wartość suwaka w czytelnej postaci, z jednostką.
  • Zmienisz wartość i zakres suwaka z kodu.
TEORIA

Zakres i wartość

MainWindow.xaml
<StackPanel Margin="20">
    <TextBlock Text="Głośność dzwonka"/>
    <Slider x:Name="Glosnosc" Minimum="0" Maximum="100" Value="40"/>
</StackPanel>
Dzwonek–□✕
Głośność dzwonka

suwak na wartości 40 z zakresu 0–100

Value ma typ double i zawsze leży między Minimum a Maximum — próba ustawienia większej wartości kończy się ustawieniem maksimum. Suwak obsługuje też klawiatura: strzałki zmieniają wartość o SmallChange (domyślnie 0,1), a PgUp/PgDn i kliknięcie w pasek obok uchwytu — o LargeChange (domyślnie 1). Atrybut Orientation="Vertical" stawia suwak pionowo.

TEORIA

Krok i podziałka

Przeciągany myszą suwak przyjmuje dowolne wartości ułamkowe, np. 40,3719. Żeby wartość „przeskakiwała” co określony krok, łączysz dwie właściwości:

MainWindow.xaml
<!-- tylko liczby całkowite od 1 do 10, kreski przy każdej -->
<Slider x:Name="Ocena" Minimum="1" Maximum="10" Value="5"
        TickFrequency="1" IsSnapToTickEnabled="True"
        TickPlacement="BottomRight" AutoToolTipPlacement="TopLeft"/>
WłaściwośćCo robi
TickFrequencyOdstęp między kreskami podziałki, np. 1, 0,5, 10.
IsSnapToTickEnabled="True"Wartość zawsze „przyskakuje” do najbliższej kreski — to ustawia krok.
TickPlacementGdzie narysować kreski: None (domyślnie — niewidoczne), TopLeft, BottomRight, Both. Kreski działają także, gdy ich nie widać.
AutoToolTipPlacementPodczas przeciągania pokazuje dymek z wartością.

Przy kroku 0,5 na zakresie 120 jednostek kresek byłoby 240 — wtedy lepiej ich nie rysować (TickPlacement zostaje None), a krok i tak działa.

TEORIA

Zdarzenie ValueChanged

Wywołuje się przy każdej zmianie wartości — podczas przeciągania nawet kilkadziesiąt razy na sekundę. Parametr ma dość długi typ RoutedPropertyChangedEventArgs<double>, który przechowuje starą i nową wartość:

MainWindow.xaml.cs
// w XAML: <Slider x:Name="Glosnosc" ... ValueChanged="Glosnosc_ValueChanged"/>
private void Glosnosc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    if (Opis == null)
    {
        return;     // Value="40" w XAML wywołało zdarzenie przed utworzeniem napisu
    }

    Opis.Text = $"Głośność: {e.NewValue:F0}%";     // to samo co Glosnosc.Value
}

Zdarzenie przy starcie okna

Value="40" w XAML zmienia wartość z domyślnego 0 na 40 i wywołuje ValueChanged w trakcie InitializeComponent(). Jeśli metoda odwołuje się do kontrolek zapisanych niżej w pliku, sprawdź na początku, czy nie są null — tak jak przy polach wyboru i listach.

TEORIA

Suwak z kodu

MainWindow.xaml.cs
Glosnosc.Value = 75;                  // przesuwa uchwyt (i wywołuje ValueChanged)
Glosnosc.Maximum = 50;                // nowy zakres — Value spada do 50
int procent = (int)Glosnosc.Value;    // double → int: ucina część ułamkową
double zaokr = Math.Round(Glosnosc.Value, 1);   // zaokrąglenie do 0,1

Pamiętaj, że Value to double. Do wyświetlania używaj formatu ({x:F0}, {x:F1}), a do obliczeń na liczbach całkowitych — rzutowania (int) albo Math.Round.

PRZYKŁAD

Kalkulator BMI z suwakami

Dwa suwaki: wzrost (120–220 cm, co 1 cm) i waga (30–150 kg, co 0,5 kg). Wskaźnik BMI, kategoria i kolor karty wyniku zmieniają się podczas przesuwania. Pod wynikiem program podaje zakres wagi, przy którym BMI jest prawidłowe dla wybranego wzrostu.

Kalkulator BMI–□✕
Wzrost170 cm
Waga65,0 kg
BMI 22,5
waga prawidłowa
Przy wzroście 170 cm BMI prawidłowe daje waga od 53,5 do 72,0 kg.
BMI to tylko orientacyjny wskaźnik dla dorosłych. U nastolatków ocenia się go na siatkach centylowych.

wartości startowe: 170 cm i 65 kg

MainWindow.xaml — pełny plik
<Window x:Class="Lekcja19.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Kalkulator BMI" SizeToContent="Height" Width="460"
        ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen">

    <StackPanel Margin="20">
        <!-- Wzrost: krok 1 cm dzięki IsSnapToTickEnabled -->
        <DockPanel>
            <TextBlock x:Name="WzrostOpis" DockPanel.Dock="Right" Width="70"
                       TextAlignment="Right" FontWeight="Bold"/>
            <TextBlock Text="Wzrost"/>
        </DockPanel>
        <Slider x:Name="Wzrost" Minimum="120" Maximum="220" Value="170"
                TickFrequency="1" IsSnapToTickEnabled="True"
                SmallChange="1" LargeChange="5"
                ValueChanged="Suwak_ValueChanged" Margin="0,4,0,16"/>

        <!-- Waga: krok 0,5 kg dzięki IsSnapToTickEnabled -->
        <DockPanel>
            <TextBlock x:Name="WagaOpis" DockPanel.Dock="Right" Width="70"
                       TextAlignment="Right" FontWeight="Bold"/>
            <TextBlock Text="Waga"/>
        </DockPanel>
        <Slider x:Name="Waga" Minimum="30" Maximum="150" Value="65"
                TickFrequency="0.5" IsSnapToTickEnabled="True"
                SmallChange="0.5" LargeChange="5"
                ValueChanged="Suwak_ValueChanged" Margin="0,4,0,16"/>

        <!-- Wynik w ramce, kolor zależny od kategorii -->
        <Border x:Name="Karta" CornerRadius="8" Padding="12">
            <StackPanel>
                <TextBlock x:Name="Bmi" FontSize="30" FontWeight="Bold"/>
                <TextBlock x:Name="Kategoria" FontSize="16"/>
                <TextBlock x:Name="Zakres" Margin="0,6,0,0" TextWrapping="Wrap"/>
            </StackPanel>
        </Border>

        <TextBlock Margin="0,10,0,0" FontSize="11" Foreground="Gray" TextWrapping="Wrap"
                   Text="BMI to tylko orientacyjny wskaźnik dla dorosłych. U nastolatków ocenia się go na siatkach centylowych."/>
    </StackPanel>
</Window>
MainWindow.xaml.cs — pełny plik
using System.Windows;
using System.Windows.Media;

namespace Lekcja19;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Przelicz();
    }

    // Oba suwaki obsługuje ta sama metoda
    private void Suwak_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        Przelicz();
    }

    private void Przelicz()
    {
        // ValueChanged przychodzi już przy ustawianiu Value w XAML
        if (Karta == null || Zakres == null)
        {
            return;
        }

        double wzrostCm = Wzrost.Value;
        double waga = Waga.Value;
        double wzrostM = wzrostCm / 100;

        double bmi = waga / (wzrostM * wzrostM);

        WzrostOpis.Text = $"{wzrostCm:F0} cm";
        WagaOpis.Text = $"{waga:F1} kg";
        Bmi.Text = $"BMI {bmi:F1}";

        if (bmi < 18.5)
        {
            Kategoria.Text = "niedowaga";
            Karta.Background = Brushes.LightBlue;
        }
        else if (bmi < 25)
        {
            Kategoria.Text = "waga prawidłowa";
            Karta.Background = Brushes.LightGreen;
        }
        else if (bmi < 30)
        {
            Kategoria.Text = "nadwaga";
            Karta.Background = Brushes.Khaki;
        }
        else
        {
            Kategoria.Text = "otyłość";
            Karta.Background = Brushes.LightSalmon;
        }

        // zakres wagi dla BMI 18,5–24,9 przy tym wzroście
        double od = 18.5 * wzrostM * wzrostM;
        double doWagi = 24.9 * wzrostM * wzrostM;
        Zakres.Text = $"Przy wzroście {wzrostCm:F0} cm BMI prawidłowe daje waga od {od:F1} do {doWagi:F1} kg.";
    }
}

Co dzieje się po kolei

  • Nad każdym suwakiem stoi DockPanel: wartość przyklejona do prawej, nazwa wypełnia resztę — nazwa jest przy lewej krawędzi, liczba przy prawej.
  • TickFrequency + IsSnapToTickEnabled ustawiają krok: 1 cm dla wzrostu i 0,5 kg dla wagi. Kresek nie widać, bo nie ma TickPlacement.
  • SmallChange i LargeChange sprawiają, że strzałki i PgUp/PgDn zmieniają wartość o sensowny krok.
  • Oba suwaki mają tę samą metodę ValueChanged, która tylko wywołuje Przelicz. Wartości odczytujemy z Value obu suwaków, a nie z e.NewValue, bo potrzebne są obie.
  • Przelicz wychodzi od razu, gdy karta wyniku jeszcze nie istnieje — Value ustawione w XAML wywołuje zdarzenie w trakcie budowania okna. Konstruktor wywołuje Przelicz jeszcze raz, gdy wszystko jest gotowe.
  • BMI = waga / wzrost², gdzie wzrost jest w metrach. Dla 170 cm i 65 kg: 65 / 2,89 ≈ 22,5.
  • Granice prawidłowej wagi to wzór odwrócony: waga = BMI × wzrost². Dla 170 cm: 18,5 × 2,89 ≈ 53,5 kg i 24,9 × 2,89 ≈ 72,0 kg.
  • Kolor karty zmienia łańcuch if/else if — progi sprawdzane są od najmniejszego.

Sprawdź trzy rzeczy

  1. Usuń IsSnapToTickEnabled="True" przy wadze i przeciągnij uchwyt. Wartość wciąż ma jedno miejsce po przecinku w napisie, ale BMI zmienia się płynnie, bo liczy się z niezaokrąglonej wartości.
  2. Dopisz do suwaka wzrostu TickPlacement="BottomRight". Pod suwakiem pojawi się 100 kresek — gęsto. Zmień TickFrequency na 10 i zobacz, jak zmienił się krok.
  3. Usuń z Przelicz warunek if (Karta == null …). Program zakończy się wyjątkiem przy starcie.
ELEMENTY WBUDOWANE

Zestawienie elementów

ElementTypCo robi
Minimum, MaximumdoubleZakres suwaka (domyślnie 0–10).
ValuedoubleBieżąca wartość, zawsze w zakresie.
SmallChange, LargeChangedoubleKrok strzałek / PgUp, PgDn i kliknięcia w pasek.
TickFrequencydoubleOdstęp kresek podziałki.
IsSnapToTickEnabledboolWartość przyskakuje do kresek.
TickPlacementNone, TopLeft, BottomRight, BothGdzie rysować kreski.
AutoToolTipPlacementNone, TopLeft, BottomRightDymek z wartością przy przeciąganiu.
OrientationHorizontal, VerticalSuwak poziomy / pionowy.
ValueChangedzdarzenieZmiana wartości; parametr RoutedPropertyChangedEventArgs<double> z OldValue i NewValue.
CZĘSTE BŁĘDY

Zanim utkniesz

ZapisProblem
ValueChanged z parametrem RoutedEventArgsBłąd: sygnatura metody nie pasuje. Typ: RoutedPropertyChangedEventArgs<double>.
int x = Suwak.Value;CS0266 — double nie zamieni się sam na int. (int)Suwak.Value.
napis „Wartość: 40,37192”Brak kroku albo formatu. Dodaj IsSnapToTickEnabled lub {x:F0}.
brak sprawdzania null w ValueChangedNullReferenceException przy starcie, gdy Value jest w XAML.
Minimum="10" Maximum="5"Suwak przyjmuje maksimum równe minimum — nie da się go przesunąć.
suwak pionowy bez wysokości w StackPanelMa bardzo małą wysokość. Daj mu Height albo postaw w wierszu *.
ZADANIA

Zadania

Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Przy każdym suwaku pokazuj jego wartość z jednostką. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.

ZAD 1Mikser kolorów z suwakami★☆☆

Wróć do mieszalnika RGB z lekcji 06, ale zamiast przycisków użyj trzech suwaków R, G, B (0–255, krok 1) i czwartego A — przezroczystość (0–255). Duży prostokąt podglądu stoi na tle w szachownicę, żeby przezroczystość była widoczna. Pod podglądem kod koloru „#80FF8800” i przycisk Szary, który ustawia R, G i B na średnią z trzech suwaków.

pokaż wskazówkę
  • Kolor z czterech składowych: Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b) — rzutowanie z double na byte.
  • Szachownicę zrobisz z UniformGrid pełnego szarych i białych ramek, a podgląd postawisz w tej samej komórce Grid na wierzchu.
ZAD 2Lupa do tekstu★☆☆

Suwak rozmiaru czcionki 8–72 (krok 1, kreski co 8) i obok pole tekstowe z liczbą. Przesuwanie suwaka zmienia liczbę w polu i rozmiar przykładowego tekstu pod spodem. Wpisanie liczby w pole (i Enter) przesuwa suwak; liczba spoza zakresu przyjmuje najbliższą granicę, a tekst zamiast liczby przywraca poprzednią wartość.

pokaż wskazówkę
  • Przypisanie wartości spoza zakresu do Value samo ją przytnie — wystarczy potem przepisać Value z powrotem do pola.
  • Enter w polu: przycisk Ustaw z IsDefault="True".
ZAD 3Rachunek w pizzerii★★☆

Pole Kwota rachunku, suwak Napiwek 0–25% z kreskami i krokiem co 5% oraz suwak Liczba osób 1–12. Na żywo: kwota napiwku, razem do zapłaty i kwota na osobę zaokrąglona w górę do 10 groszy. Pod spodem: „Zaokrąglenie dało 0,20 zł nadwyżki”. Przy błędnej kwocie zamiast wyników pokaż podpowiedź.

pokaż wskazówkę
  • Licz na decimal — wartości suwaków zamień przez (decimal)Suwak.Value.
  • Nadwyżka = kwota na osobę × liczba osób − razem.
ZAD 4Termostat★★☆

Pionowy suwak temperatury 15–28 °C z krokiem 0,5 °C, obok duża liczba „21,5 °C”, której kolor zmienia się z niebieskiego (poniżej 19), przez zielony, do czerwonego (powyżej 24). Pole wyboru Tryb eko ogranicza maksimum do 21 °C — jeśli temperatura była wyższa, suwak sam zjeżdża do 21 i pojawia się informacja „Obniżono do 21 °C (tryb eko)”. Przyciski Noc (18 °C) i Dzień (21 °C) ustawiają gotowe wartości.

pokaż wskazówkę
  • Pionowy suwak potrzebuje wysokości, np. Height="200". Krok ustawiasz jak w przykładzie: TickFrequency i IsSnapToTickEnabled.
  • Zmiana Maximum z kodu sama przytnie Value; porównaj wartość przed i po, żeby wiedzieć, czy pokazać informację.
ZAD 5Skarbonka na wakacje★★☆

Uczeń planuje oszczędności: pole Cel (np. 2400 zł), suwak Miesięczna wpłata 50–1000 zł (co 50 zł) i suwak Liczba miesięcy 1–24. Program na żywo pokazuje, ile uzbiera, czy cel zostanie osiągnięty, a jeśli nie — ile miesięcy potrzeba przy tej wpłacie i jaka wpłata wystarczy w wybranym czasie (zaokrąglona w górę do 50 zł). Wynik w ramce zielonej albo pomarańczowej.

pokaż wskazówkę
  • Potrzebne miesiące: dzielenie z zaokrągleniem w górę — Math.Ceiling(cel / wplata).
  • Wpłata do 50 zł w górę: Math.Ceiling(kwota / 50) * 50.
ZAD 6Korektor dźwięku★★★

Pięć pionowych suwaków pasm (60 Hz, 230 Hz, 910 Hz, 3,6 kHz, 14 kHz), każdy od −12 do +12 dB z krokiem 1 i kreską na zerze, pod każdym wartość „+3 dB”. Nad suwakami lista rozwijana ustawień: Płaski, Bas, Wokal, Rock, Własny. Wybór ustawienia przesuwa wszystkie suwaki na wartości zapisane w tablicy. Gdy użytkownik ręcznie przesunie dowolny suwak, lista sama przełącza się na Własny (ale nie wtedy, gdy suwaki przesuwa wybór ustawienia). Przycisk Wyzeruj ustawia Płaski.

Korektor–□✕
Rock▾
+5 dB
60 Hz
+3 dB
230 Hz
−1 dB
910 Hz
+3 dB
3,6 kHz
+5 dB
14 kHz
pokaż wskazówkę
  • Ustawienia zapisz w tablicy int[,] (ustawienie × pasmo), a suwaki włóż do panelu i odczytuj przez Children[i].
  • Pole klasy bool ustawiamZKodu: ustaw je na true przed przesuwaniem suwaków z listy i na false po — w ValueChanged przełączaj listę na Własny tylko, gdy jest false.
PODSUMOWANIE

Co trzeba zapamiętać

  • Slider wybiera liczbę z zakresu Minimum–Maximum; Value to double i zawsze mieści się w zakresie.
  • Krok = TickFrequency + IsSnapToTickEnabled; kreski pokaże TickPlacement.
  • ValueChanged ma parametr RoutedPropertyChangedEventArgs<double> i przychodzi także przy starcie okna.
  • Wartość wyświetlaj z formatem i jednostką; do liczb całkowitych użyj (int) lub Math.Round.
  • Suwak sam pilnuje zakresu — nie trzeba sprawdzać danych jak w polu tekstowym.

Dokumentacja: Microsoft Learn — klasa Slider.

Postęp zapisuje się w tej przeglądarce.