C# · WPF · INF.04 · Kontrolki

Button – przycisk

Poznasz Button – najczęściej używaną kontrolkę interaktywną w WPF. Nauczysz się obsługiwać kliknięcia, tworzyć przyciski z ikonami, wyłączać je i dodawać podpowiedzi.

Button Click IsEnabled ToolTip
1

Czym jest Button?

Button to klikalny przycisk – jedna z najważniejszych kontrolek w każdej aplikacji okienkowej. Użytkownik klika, a Twój kod C# reaguje wykonując określoną akcję.

Najprostszy przycisk

Wystarczy podać Content (treść) i podpiąć obsługę Click:

Minimalny przycisk
<Button Content="Kliknij mnie"
        Click="Przycisk_Click" />
C# – obsługa kliknięcia
private void Przycisk_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Kliknięto przycisk!");
}
2

Content – zawartość przycisku

Tekst jako Content

Najczęściej Content to po prostu tekst, podany jako atrybut.

Przyciski z tekstem
<Button Content="Zapisz"  Width="100" />
<Button Content="Anuluj" Width="100" />
<Button Content="Usuń"   Width="100" />

Content jako dowolny element

Właściwość Content to nie tylko tekst – może przyjąć dowolny element WPF. To znaczy, że przycisk może zawierać obraz, kombinację tekstu i ikony, nawet cały StackPanel z kilkoma elementami.

Content jako złożony element (zapis elementowy)
<Button Width="140" Height="40">
    <Button.Content>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="💾" Margin="0,0,6,0" />
            <TextBlock Text="Zapisz plik" />
        </StackPanel>
    </Button.Content>
</Button>
Dlaczego to działa?

Button dziedziczy po ContentControl – klasie, która może wyświetlić cokolwiek jako swoją zawartość. To ta sama mechanika, dzięki której wewnątrz przycisku można umieścić obraz, ikonę razem z tekstem, czy nawet animację.

3

Zdarzenie Click

Podpięcie w XAML

Są dwa sposoby podpięcia obsługi kliknięcia: wpisanie nazwy metody ręcznie w XAML, albo kliknięcie dwukrotne na przycisku w designerze Visual Studio (które zrobi to automatycznie).

Podpięcie Click
<Button x:Name="btnZapisz"
        Content="Zapisz"
        Click="btnZapisz_Click" />
C# – sygnatura metody obsługującej Click
private void btnZapisz_Click(object sender, RoutedEventArgs e)
{
    // Twój kod tutaj
    MessageBox.Show("Zapisano!");
}
sender i e – co to jest?

sender to obiekt, który wywołał zdarzenie – w tym przypadku klikany przycisk. e to dodatkowe informacje o zdarzeniu. Najczęściej ich nie potrzebujesz, ale sender przydaje się gdy kilka przycisków używa tej samej metody (patrz niżej).

Wspólna metoda dla wielu przycisków

Jeśli kilka przycisków ma podobną logikę, możesz podpiąć je do tej samej metody i rozróżnić który został kliknięty za pomocą sender.

XAML – kilka przycisków, jedna metoda
<Button Content="Poniedziałek" Click="DzienTygodnia_Click" />
<Button Content="Wtorek"      Click="DzienTygodnia_Click" />
<Button Content="Środa"       Click="DzienTygodnia_Click" />
C# – rozróżnianie przycisku przez sender
private void DzienTygodnia_Click(object sender, RoutedEventArgs e)
{
    // Rzutujemy sender na Button, żeby odczytać który był kliknięty
    Button klikniety = (Button)sender;
    string dzien = klikniety.Content.ToString();

    lblWynik.Text = $"Wybrano: {dzien}";
}
4

IsEnabled – włączanie i wyłączanie

IsEnabled kontroluje czy przycisk jest aktywny. Wyłączony przycisk (IsEnabled="False") jest wyszarzony i nie reaguje na kliknięcia.

Przycisk domyślnie wyłączony
<Button x:Name="btnWyslij"
        Content="Wyślij"
        IsEnabled="False" />

Najczęstszy wzorzec: przycisk jest wyłączony do momentu, gdy użytkownik wypełni wymagane pole.

Włączanie przycisku po wypełnieniu pola
// XAML: <TextBox x:Name="txtEmail" TextChanged="txtEmail_TextChanged" />
//       <Button x:Name="btnWyslij" IsEnabled="False" />

private void txtEmail_TextChanged(object sender, TextChangedEventArgs e)
{
    // Przycisk aktywny tylko gdy pole nie jest puste
    btnWyslij.IsEnabled = !string.IsNullOrWhiteSpace(txtEmail.Text);
}

Inny częsty przypadek: wyłączenie przycisku po kliknięciu, żeby zapobiec wielokrotnemu wysłaniu tej samej akcji (np. wielokrotne zamówienie po szybkim klikaniu).

Wyłączenie przycisku po kliknięciu
private void btnZamow_Click(object sender, RoutedEventArgs e)
{
    btnZamow.IsEnabled = false;        // blokujemy ponowne kliknięcie
    btnZamow.Content   = "Przetwarzanie...";

    // (tu logika zamówienia)

    MessageBox.Show("Zamówienie złożone!");
    btnZamow.Content   = "Zamów";
    btnZamow.IsEnabled = true;
}
Visibility a IsEnabled – to nie to samo!

IsEnabled="False" – przycisk jest widoczny, ale wyszarzony i nieaktywny.
Visibility="Collapsed" – przycisk jest całkowicie niewidoczny, jakby go nie było.
Wybierz IsEnabled, gdy chcesz pokazać użytkownikowi, że opcja istnieje, ale jest niedostępna. Wybierz Visibility, gdy opcja ma być całkowicie skryta.

5

IsDefault i IsCancel – obsługa Enter i Esc

Te dwie właściwości pozwalają obsłużyć przycisk klawiaturą bez pisania żadnego kodu – działają automatycznie.

WłaściwośćKlawiszDziałanie
IsDefault="True"EnterNaciśnięcie Enter w oknie „klika” ten przycisk
IsCancel="True"EscNaciśnięcie Esc w oknie „klika” ten przycisk
Typowe okno dialogowe z IsDefault / IsCancel
<StackPanel Orientation="Horizontal"
            HorizontalAlignment="Right">

    <Button Content="Anuluj"
            IsCancel="True"
            Width="80"
            Margin="0,0,8,0"
            Click="btnAnuluj_Click" />

    <Button Content="OK"
            IsDefault="True"
            Width="80"
            Click="btnOK_Click" />

</StackPanel>
<!-- Enter = kliknie OK, Esc = kliknie Anuluj –
     niezależnie od tego, który element ma focus -->
Kiedy używać

IsDefault ustawiaj na przycisku, który wykonuje „pozytywną” akcję (OK, Zapisz, Zaloguj). IsCancel na przycisku zamykającym/odwołującym (Anuluj, Zamknij). Dzięki temu formularz da się obsłużyć w pełni klawiaturą – ważne dla wygody i dostępności (accessibility).

6

ToolTip – podpowiedź po najechaniu

ToolTip to mały żółty komunikat, który pojawia się po najechaniu kursorem na element i chwili oczekiwania. Przydaje się do wyjaśniania znaczenia przycisków – zwłaszcza tych z samą ikoną, bez tekstu.

Prosty ToolTip
<Button Content="🗑"
        Width="40"
        ToolTip="Usuń wybrany element" />

<Button Content="💾"
        Width="40"
        ToolTip="Zapisz zmiany (Ctrl+S)" />

ToolTip może też być złożonym elementem – nie tylko tekstem.

Rozbudowany ToolTip
<Button Content="Eksportuj">
    <Button.ToolTip>
        <StackPanel>
            <TextBlock Text="Eksport danych" FontWeight="Bold" />
            <TextBlock Text="Zapisuje dane do pliku CSV" Foreground="Gray" />
        </StackPanel>
    </Button.ToolTip>
</Button>
7

Przycisk z ikoną

Emoji jako ikona – najprostszy sposób

Najprostszym sposobem dodania ikony jest użycie emoji w tekście. Nie wymaga żadnych plików graficznych i działa od razu.

Przyciski z emoji
<Button Content="➕ Dodaj"     Width="100" />
<Button Content="🗑 Usuń"      Width="100" />
<Button Content="✏️ Edytuj"    Width="100" />
<Button Content="💾 Zapisz"    Width="100" />
<Button Content="🔍 Szukaj"    Width="100" />
<Button Content="⚙️ Ustawienia" Width="110" />

Obraz + tekst (Image + TextBlock)

Dla bardziej profesjonalnego wyglądu możesz użyć prawdziwego pliku graficznego razem z tekstem, łącząc je w StackPanel.

Przycisk z obrazem i tekstem
<Button Width="140" Height="40">
    <StackPanel Orientation="Horizontal">
        <Image Source="/Images/save.png"
               Width="20"
               Height="20"
               Margin="0,0,8,0" />
        <TextBlock Text="Zapisz"
                   VerticalAlignment="Center" />
    </StackPanel>
</Button>

Tylko ikona, bez tekstu – dobry do przycisków w toolbarach. Wtedy koniecznie dodaj ToolTip, żeby użytkownik wiedział co robi przycisk.

Tylko ikona + ToolTip
<Button Width="36" Height="36"
        ToolTip="Usuń wybrany element">
    <Image Source="/Images/delete.png" Width="18" Height="18" />
</Button>
8

Wygląd przycisku

Podstawowy wygląd przycisku możesz dostosować bez wnikania w zaawansowane style i szablony (te poznasz w dalszych tematach).

Podstawowe właściwości wizualne
<Button Content="Zapisz zmiany"
        Width="150"
        Height="40"
        Background="#2ecc71"
        Foreground="White"
        FontSize="14"
        FontWeight="Bold"
        BorderThickness="0"
        Cursor="Hand" />
WłaściwośćCo zmienia
BackgroundKolor tła przycisku
ForegroundKolor tekstu
BorderBrushKolor obramowania
BorderThicknessGrubość obramowania (0 = bez ramki)
PaddingWewnętrzny odstęp treści od krawędzi
CursorKształt kursora po najechaniu ("Hand" = łapka)
OpacityPrzezroczystość (0.0 – 1.0)
Kolorowe przyciski statusów – gotowe wzorce

Przydatny zestaw kolorów dla przycisków akcji:

Paleta kolorów dla typowych akcji
<Button Content="Zapisz"  Background="#2ecc71" Foreground="White" />  <!-- zielony – sukces -->
<Button Content="Usuń"   Background="#e74c3c" Foreground="White" />  <!-- czerwony – niebezpieczna akcja -->
<Button Content="Edytuj"  Background="#3498db" Foreground="White" />  <!-- niebieski – neutralna akcja -->
<Button Content="Anuluj"  Background="#95a5a6" Foreground="White" />  <!-- szary – mniej istotna akcja -->
<Button Content="Ostrzeżenie" Background="#f39c12" Foreground="White" /> <!-- pomarańcz – uwaga -->
9

Przyciski tworzone w C#

Tak jak inne kontrolki, Button możesz w pełni stworzyć i skonfigurować z kodu C#. Przydaje się to gdy liczba przycisków zależy od danych.

Dynamiczne tworzenie przycisków
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    string[] kategorie = { "Elektronika", "Odzież", "Sport", "Książki" };

    foreach (string kategoria in kategorie)
    {
        Button btn = new Button();
        btn.Content = kategoria;
        btn.Width   = 120;
        btn.Height  = 35;
        btn.Margin  = new Thickness(5);
        btn.Tag     = kategoria;          // zapamiętujemy kategorię
        btn.Click  += Kategoria_Click;   // podpinamy obsługę

        panelKategorii.Children.Add(btn);
    }
}

private void Kategoria_Click(object sender, RoutedEventArgs e)
{
    Button klikniety = (Button)sender;
    string kategoria = (string)klikniety.Tag;
    lblWynik.Text = $"Wybrana kategoria: {kategoria}";
}
+= a nie = przy podpinaniu zdarzeń

Zwróć uwagę na btn.Click += Kategoria_Click; – używamy +=, nie =. To dlatego, że do jednego zdarzenia można podpiąć wiele metod (choć w praktyce zwykle podpinamy jedną). Operator = przy zdarzeniach w C# nie istnieje – kompilator zgłosi błąd.

10

Częste błędy

❌ Błąd 1: Literówka w nazwie metody Click

❌ Nazwa się nie zgadza

<!-- XAML: -->
<Button Click="btnZapisz_Click" />

// C#:
private void btnZapsiz_Click(...) // literówka!
{ }
// Błąd kompilacji

✅ Pozwól Visual Studio wygenerować

Kliknij dwukrotnie przycisk w designerze XAML – Visual Studio sam utworzy metodę z poprawną nazwą i podpięciem.

❌ Błąd 2: Zapominanie o sprawdzeniu null przy rzutowaniu sender

❌ Zbyt pewne rzutowanie

private void Wspolna_Click(object sender, ...)
{
    Button btn = (Button)sender;
    string tag = (string)btn.Tag;
    // Jeśli Tag nie był ustawiony (null) –
    // rzutowanie wyrzuci wyjątek!
}

✅ Sprawdzenie przed rzutowaniem

private void Wspolna_Click(object sender, ...)
{
    Button btn = (Button)sender;
    if (btn.Tag == null) return;
    string tag = (string)btn.Tag;
}

❌ Błąd 3: Brak ToolTip na przycisku tylko z ikoną

❌ Niejasne znaczenie przycisku

<Button Content="🗑" Width="36" />
<!-- Co robi ten przycisk?
     Użytkownik musi zgadywać -->

✅ ToolTip wyjaśnia funkcję

<Button Content="🗑" Width="36"
        ToolTip="Usuń element" />

❌ Błąd 4: Niewyłączony przycisk podczas długiej operacji

❌ Można kliknąć wiele razy

private void btnWyslij_Click(...)
{
    // Brak IsEnabled = false
    // Użytkownik może kliknąć
    // kilka razy zanim operacja się skończy
    WyslijDane();
}

✅ Blokada na czas operacji

private void btnWyslij_Click(...)
{
    btnWyslij.IsEnabled = false;
    WyslijDane();
    btnWyslij.IsEnabled = true;
}
11

Zadania do wykonania

Zadanie 1 łatwe

Stwórz okno z trzema przyciskami: „➕ Dodaj”, „✏️ Edytuj”, „🗑 Usuń”, każdy w innym kolorze (zielony, niebieski, czerwony) z białym tekstem. Każdy ma ToolTip wyjaśniający jego funkcję. Kliknięcie każdego wyświetla odpowiedni MessageBox.

Zadanie 2 łatwe

Stwórz formularz logowania: TextBox na login, PasswordBox na hasło, przycisk „Zaloguj” z IsDefault="True" i przycisk „Anuluj” z IsCancel="True". Przycisk „Zaloguj” jest wyłączony (IsEnabled="False") dopóki obydwa pola nie są wypełnione – użyj TextChanged i PasswordChanged.

Zadanie 3 średnie

W C# dynamicznie wygeneruj 10 przycisków z liczbami 1-10 w WrapPanel. Każdy przycisk po kliknięciu dodaje swoją wartość do sumy wyświetlanej w TextBlock. Dodaj przycisk „Reset”, który zeruje sumę. Użyj wspólnej metody obsługującej wszystkie przyciski z liczbami (rozróżniaj przez sender i Tag).

Zadanie 4 średnie

Stwórz prosty quiz z jednym pytaniem i czterema przyciskami odpowiedzi (A, B, C, D). Po kliknięciu poprawnej odpowiedzi przycisk natychmiast zmienia tło na zielone i wyświetla „Poprawnie!”. Po kliknięciu błędnej – tło czerwone, wszystkie przyciski się blokują (IsEnabled = false), a poprawna odpowiedź też podświetla się na zielono.