Slider – suwak
Poznasz Slider – kontrolkę do wybierania wartości liczbowej przez przesuwanie uchwytu. Nauczysz się ustawiać zakres, kroki skokowe i powiązywać suwak z innymi kontrolkami na żywo.
Czym jest Slider?
Slider to suwak – kontrolka, w której użytkownik wybiera wartość liczbową, przesuwając uchwyt wzdłuż linii. Znasz go z regulacji głośności, jasności ekranu, czy ustawień w grach komputerowych.
Slider jest świetny, gdy ważny jest szybki, intuicyjny wybór z określonego zakresu (głośność, jasność, procent). TextBox lepiej sprawdza się, gdy potrzebna jest precyzyjna, konkretna wartość wpisana z klawiatury (cena, wiek, dokładna liczba).
<Slider x:Name="sldGlosnosc" Width="200" /> <!-- Domyślnie: Minimum=0, Maximum=10 -->
Minimum, Maximum, Value
Trzy najważniejsze właściwości Slidera określają jego zakres i aktualną wartość.
| Właściwość | Co określa | Wartość domyślna |
|---|---|---|
Minimum | Najmniejsza możliwa wartość | 0 |
Maximum | Największa możliwa wartość | 10 |
Value | Aktualna wartość suwaka | 0 |
<!-- Głośność: 0-100, startowo 50 --> <Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" Width="250" /> <!-- Temperatura: -20 do 40 stopni --> <Slider x:Name="sldTemperatura" Minimum="-20" Maximum="40" Value="20" Width="250" /> <!-- Ocena gwiazdkowa: 1-5 --> <Slider x:Name="sldOcena" Minimum="1" Maximum="5" Value="3" Width="150" />
Właściwość Value jest typu double –
domyślnie suwak może przyjąć wartości z przecinkiem (np. 47.36),
nie tylko liczby całkowite. Jeśli chcesz tylko liczb całkowitych,
użyj IsSnapToTickEnabled opisanego w sekcji 4.
Orientation – kierunek suwaka
Domyślnie Slider jest poziomy. Możesz go obrócić na pionowy
ustawiając Orientation="Vertical" – wtedy musisz też
zwykle ustawić Height zamiast Width.
<!-- Poziomy (domyślny) --> <Slider Orientation="Horizontal" Minimum="0" Maximum="100" Width="250" /> <!-- Pionowy – jak korektor graficzny w odtwarzaczu muzyki --> <Slider Orientation="Vertical" Minimum="0" Maximum="100" Height="200" />
Znaczki skali – TickFrequency
TickFrequency ustawia odstęp między małymi znaczkami
(kreseczkami) widocznymi na suwaku – pomagają one wizualnie
ocenić wybraną wartość bez patrzenia na liczbę.
TickPlacement – gdzie pokazać znaczki
| Wartość | Gdzie pokazują się znaczki |
|---|---|
None (domyślne) | Brak znaczków |
TopLeft | Nad suwakiem (lub po lewej przy pionowym) |
BottomRight | Pod suwakiem (lub po prawej przy pionowym) |
Both | Z obu stron |
<Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" TickFrequency="10" TickPlacement="BottomRight" Width="250" /> <!-- Znaczki widoczne przy 0, 10, 20, 30 ... 100 -->
IsSnapToTickEnabled – przyciąganie do znaczków
Sam TickFrequency tylko rysuje znaczki –
nie ogranicza wartości. Żeby suwak faktycznie skakał
tylko po znaczkach (np. tylko wielokrotności 10), potrzebujesz
dodatkowo IsSnapToTickEnabled="True".
<Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" TickFrequency="10" TickPlacement="BottomRight" IsSnapToTickEnabled="True" Width="250" /> <!-- Teraz Value będzie wyłącznie wielokrotnością 10: 0, 10, 20, 30 ... 100 – nigdy np. 47 -->
Częste zastosowanie IsSnapToTickEnabled to ocena
w skali 1-5 lub 1-10 – nie chcemy, żeby użytkownik mógł wybrać
„3.7 gwiazdki”. Ustawienie TickFrequency="1" razem
z IsSnapToTickEnabled="True" daje skok po każdej liczbie całkowitej.
<Slider x:Name="sldOcena" Minimum="1" Maximum="5" Value="3" TickFrequency="1" TickPlacement="BottomRight" IsSnapToTickEnabled="True" Width="180" /> <!-- Wartości: tylko 1, 2, 3, 4 lub 5 -->
Zdarzenie ValueChanged
ValueChanged odpala się za każdym razem gdy zmienia się
wartość suwaka – podczas przesuwania, kliknięcia na linii,
a także po ustawieniu wartości z kodu C#.
<Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" Width="250" ValueChanged="sldGlosnosc_ValueChanged" />
private void sldGlosnosc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // e.NewValue – nowa wartość, e.OldValue – wartość przed zmianą double nowaWartosc = e.NewValue; lblGlosnosc.Text = $"Głośność: {nowaWartosc:F0}%"; }
Nie musisz pamiętać tej nazwy – Visual Studio wygeneruje ją
automatycznie po dwukrotnym kliknięciu pola ValueChanged
we właściwościach Slidera w designerze. Najważniejsze to e.NewValue,
czyli aktualna wartość po zmianie.
Gdy XAML ustawia Value="50", zdarzenie ValueChanged
odpala się natychmiast przy tworzeniu okna.
Jeśli metoda obsługująca odwołuje się do innych kontrolek
(np. lblGlosnosc), które jeszcze nie istnieją –
dodaj zabezpieczenie if (lblGlosnosc == null) return;.
Powiązanie z TextBlock na żywo
Najczęstszy wzorzec użycia Slidera: pokazujesz aktualną wartość liczbową obok suwaka, żeby użytkownik widział precyzyjnie co właśnie wybrał.
<StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Głośność: " VerticalAlignment="Center" /> <TextBlock x:Name="lblWartosc" Text="50%" FontWeight="Bold" Foreground="SteelBlue" VerticalAlignment="Center" /> </StackPanel> <Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" Width="250" ValueChanged="sldGlosnosc_ValueChanged" /> </StackPanel>
private void sldGlosnosc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (lblWartosc == null) return; lblWartosc.Text = $"{e.NewValue:F0}%"; }
{e.NewValue:F0} formatuje liczbę z przecinkiem
jako liczbę całkowitą (0 cyfr po przecinku).
:F1 dałoby jedno miejsce po przecinku (np. „47.3″),
:F2 – dwa miejsca (np. „47.36″). Format F
oznacza „fixed point” (liczba zmiennoprzecinkowa o ustalonej precyzji).
Możesz też zrobić odwrotną synchronizację – TextBox jako edytowalne pole, które aktualizuje Slider:
private bool _aktualizujeProgramowo = false; private void sldGlosnosc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (_aktualizujeProgramowo) return; _aktualizujeProgramowo = true; txtGlosnosc.Text = $"{e.NewValue:F0}"; _aktualizujeProgramowo = false; } private void txtGlosnosc_TextChanged(object sender, TextChangedEventArgs e) { if (_aktualizujeProgramowo) return; if (double.TryParse(txtGlosnosc.Text, out double wartosc)) { _aktualizujeProgramowo = true; sldGlosnosc.Value = wartosc; _aktualizujeProgramowo = false; } }
Kroki – SmallChange i LargeChange
Te właściwości kontrolują o ile zmieni się wartość Slidera po naciśnięciu klawiszy strzałek albo kliknięciu na linię suwaka (bez przesuwania uchwytu).
| Właściwość | Kiedy działa | Wartość domyślna |
|---|---|---|
SmallChange | Strzałki ⬅️➡️ na klawiaturze (gdy Slider ma focus) | 0.1 × (Maximum - Minimum) |
LargeChange | Kliknięcie na linię suwaka poza uchwytem | (Maximum - Minimum) |
<Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="50" SmallChange="1" <!-- strzałka: +/- 1 --> LargeChange="10" <!-- klik na linię: +/- 10 --> Width="250" />
Slider w C#
// Odczyt aktualnej wartości double glosnosc = sldGlosnosc.Value; // Ustawienie wartości z kodu (np. po wczytaniu zapisanych ustawień) sldGlosnosc.Value = 75; // Zmiana zakresu w czasie działania programu sldGlosnosc.Minimum = 0; sldGlosnosc.Maximum = 200; // Reset do wartości minimalnej sldGlosnosc.Value = sldGlosnosc.Minimum; // Konwersja na int, gdy potrzebujesz liczby całkowitej int glosnoscInt = (int)sldGlosnosc.Value;
Praktyczne przykłady
Regulacja głośności z ikoną
<StackPanel Orientation="Horizontal" Margin="10"> <TextBlock x:Name="lblIkona" Text="🔊" FontSize="18" Margin="0,0,8,0" VerticalAlignment="Center" /> <Slider x:Name="sldGlosnosc" Minimum="0" Maximum="100" Value="60" Width="150" VerticalAlignment="Center" ValueChanged="sldGlosnosc_ValueChanged" /> <TextBlock x:Name="lblWartosc" Text="60%" Width="40" Margin="8,0,0,0" VerticalAlignment="Center" /> </StackPanel>
private void sldGlosnosc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (lblWartosc == null) return; lblWartosc.Text = $"{e.NewValue:F0}%"; // Zmieniamy ikonę głośnika w zależności od wartości if (e.NewValue == 0) lblIkona.Text = "🔇"; else if (e.NewValue < 50) lblIkona.Text = "🔉"; else lblIkona.Text = "🔊"; }
Mieszacz kolorów RGB
Trzy slidery (Red, Green, Blue) sterujące kolorem tła – klasyczne ćwiczenie łączące Slider z manipulacją kolorami.
<StackPanel Margin="20"> <TextBlock Text="Red" /> <Slider x:Name="sldRed" Minimum="0" Maximum="255" Value="128" ValueChanged="Kolor_ValueChanged" /> <TextBlock Text="Green" Margin="0,8,0,0" /> <Slider x:Name="sldGreen" Minimum="0" Maximum="255" Value="128" ValueChanged="Kolor_ValueChanged" /> <TextBlock Text="Blue" Margin="0,8,0,0" /> <Slider x:Name="sldBlue" Minimum="0" Maximum="255" Value="128" ValueChanged="Kolor_ValueChanged" /> <Border x:Name="borderKolor" Height="80" Margin="0,16,0,0" CornerRadius="8" /> <TextBlock x:Name="lblKodKoloru" Text="#808080" HorizontalAlignment="Center" Margin="0,8,0,0" /> </StackPanel>
private void Kolor_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (borderKolor == null) return; byte r = (byte)sldRed.Value; byte g = (byte)sldGreen.Value; byte b = (byte)sldBlue.Value; Color kolor = Color.FromRgb(r, g, b); borderKolor.Background = new SolidColorBrush(kolor); lblKodKoloru.Text = $"#{r:X2}{g:X2}{b:X2}"; }
{r:X2} formatuje liczbę jako szesnastkową (hex),
z minimum 2 cyframi (uzupełnia zerem jeśli trzeba).
128 w formacie X2 da "80" –
dlatego trzy takie wartości razem dają standardowy kod koloru
jak #808080.
Częste błędy
❌ Błąd 1: TickFrequency bez IsSnapToTickEnabled
❌ Znaczki widoczne, ale nie działają
<Slider TickFrequency="10"
TickPlacement="BottomRight" />
<!-- Znaczki na 0,10,20...
ale wartość wciąż może być
np. 23.7! -->
✅ Razem z IsSnapToTickEnabled
<Slider TickFrequency="10"
TickPlacement="BottomRight"
IsSnapToTickEnabled="True" />
❌ Błąd 2: ValueChanged odpalający się przed inicjalizacją kontrolek
❌ Wyjątek przy starcie okna
private void sld_ValueChanged(...)
{
// lblWartosc może być null
// gdy XAML ustawia Value="50"
// podczas tworzenia okna!
lblWartosc.Text = "...";
}
✅ Zabezpieczenie null
private void sld_ValueChanged(...)
{
if (lblWartosc == null) return;
lblWartosc.Text = "...";
}
❌ Błąd 3: Rzutowanie double na int bez przemyślenia
❌ Utrata precyzji niezauważona
int wartosc = (int)sldOcena.Value; // Jeśli Value = 3.9, wynik to 3! // Rzutowanie (int) zawsze // OBCINA, nie zaokrągla
✅ Math.Round gdy potrzebne zaokrąglenie
int wartosc = (int)Math.Round(sldOcena.Value); // 3.9 zaokrągli się do 4 // Lub po prostu użyj // IsSnapToTickEnabled="True", // żeby Value było zawsze całkowite
❌ Błąd 4: Zapomniany format liczby w TextBlock
❌ Brzydki wynik z wielu cyfr po przecinku
lblWartosc.Text = $"{e.NewValue}%";
// Wyświetli np. "47.36281%" –
// nieczytelne dla użytkownika
✅ Formatowanie do liczby całkowitej
lblWartosc.Text = $"{e.NewValue:F0}%";
// Wyświetli "47%"
Zadania do wykonania
Stwórz Slider regulujący jasność (0-100) z TextBlock pokazującym aktualną wartość w formacie „Jasność: 75%” aktualizowanym na żywo. Gdy wartość spadnie poniżej 20, TextBlock ma zmienić kolor na czerwony (ostrzeżenie „bardzo ciemno”), powyżej – na normalny.
Stwórz Slider oceny produktu w skali 1-5 z
IsSnapToTickEnabled="True" i TickFrequency="1".
Pod suwakiem wyświetl odpowiednią liczbę gwiazdek (np. dla wartości 3:
„⭐⭐⭐☆☆”), aktualizowaną przy każdej zmianie.
Zbuduj kompletny mieszacz kolorów RGB (jak w sekcji 9b) z trzema sliderami, podglądem koloru w Border i kodem szesnastkowym. Dodaj dodatkowo przyciski z trzema gotowymi kolorami (np. „Czerwień”, „Zieleń”, „Błękit”), które po kliknięciu ustawiają wszystkie trzy slidery na odpowiednie wartości.
Stwórz kalkulator raty kredytu: dwa slidery – kwota kredytu (1000-100000 zł, krok 1000) i liczba miesięcy (6-60, krok 6). Pod suwakami wyświetl obliczoną miesięczną ratę (prosty wzór: kwota / liczba miesięcy, bez odsetek) oraz całkowitą kwotę do spłaty. Wynik aktualizuje się przy zmianie obu sliderów.