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

Właściwości wspólne kontrolek

Napis, przycisk i panel mają różne zadania, ale wiele wspólnych ustawień: odstępy, wyrównanie, rozmiar, widoczność i dostępność. Gdy raz je poznasz, użyjesz ich w każdej kontrolce do końca kursu — i na egzaminie, gdzie arkusz często podaje dokładne marginesy, rozmiary i wyrównanie. Nauczysz się też chować elementy, blokować przyciski i zmieniać czcionkę całego okna jedną linią.

C# XAML Margin Padding Visibility IsEnabled 90 min
CEL LEKCJI

Czego się dziś nauczysz

  • Odróżnisz Margin od Padding i zapiszesz je jedną, dwiema lub czterema liczbami.
  • Ustawisz położenie kontrolki przez HorizontalAlignment i VerticalAlignment i przewidzisz efekt w StackPanel.
  • Ograniczysz rozmiar przez Width, MinWidth, MaxWidth.
  • Wyjaśnisz różnicę między Hidden a Collapsed.
  • Zablokujesz kontrolkę przez IsEnabled i dodasz podpowiedź ToolTip.
  • Zmienisz te właściwości z C# i wykorzystasz dziedziczenie czcionki po oknie.
TEORIA

Po co wspólne właściwości

W arkuszu egzaminacyjnym często czytasz: „przycisk wyrównany do prawej, szerokość 120, odstęp 10 od pola”, „po zatwierdzeniu formularz ma zniknąć”, „przycisk nieaktywny, dopóki…”. Każde z tych wymagań to jedna z właściwości, które mają wszystkie kontrolki — bo dziedziczą je po wspólnej klasie bazowej FrameworkElement. Nie trzeba ich uczyć się osobno dla napisu i dla przycisku.

TEORIA

Margin i Padding

Margin to odstęp na zewnątrz kontrolki — odsuwa ją od sąsiadów. Padding to odstęp wewnątrz — między ramką kontrolki a jej zawartością (np. tekstem przycisku).

Margin
Padding Zapisz

przycisk: przerywana linia to granica marginesu, ramka to krawędź przycisku

ZapisZnaczenieKiedy
Margin="10"10 ze wszystkich stronrówny odstęp dookoła
Margin="20,5"20 lewo i prawo, 5 góra i dółodstęp poziomy inny niż pionowy
Margin="0,10,0,20"lewo, góra, prawo, dółkażda strona osobno

Te same trzy zapisy działają dla Padding. Pamiętaj, że marginesy sąsiadów się sumują: dwa przyciski z Margin="10" jeden pod drugim są odsunięte o 20. Padding mają kontrolki z ramką lub tłem — Button, TextBlock; panele (StackPanel) go nie mają, więc ich zawartość odsuwasz marginesem panelu.

TEORIA

Wyrównanie w poziomie i w pionie

Każda kontrolka dostaje od panelu obszar. HorizontalAlignment i VerticalAlignment mówią, jak ma się w nim ułożyć:

MainWindow.xaml
<StackPanel Margin="15">
    <Button Content="Left"    HorizontalAlignment="Left"    Margin="0,0,0,6"/>
    <Button Content="Center"  HorizontalAlignment="Center"  Margin="0,0,0,6"/>
    <Button Content="Right"   HorizontalAlignment="Right"   Margin="0,0,0,6"/>
    <Button Content="Stretch" HorizontalAlignment="Stretch"/>
</StackPanel>
Wyrównanie–□✕
Left
Center
Right
Stretch

Stretch to wartość domyślna — dlatego przyciski w pionowym panelu rozciągają się na całą szerokość

WłaściwośćWartościUwagi
HorizontalAlignmentLeft, Center, Right, StretchDomyślnie Stretch.
VerticalAlignmentTop, Center, Bottom, StretchW pionowym StackPanel nie ma efektu — panel daje kontrolce tyle wysokości, ile potrzebuje.
HorizontalContentAlignmentjak wyżejWyrównanie zawartości wewnątrz kontrolki, np. tekstu w szerokim przycisku.
TEORIA

Rozmiar: stały, minimalny, maksymalny

WłaściwośćCo robi
Width, HeightStały rozmiar. Ma pierwszeństwo przed Stretch.
MinWidth, MinHeightKontrolka nie będzie mniejsza, nawet przy krótkim tekście.
MaxWidth, MaxHeightKontrolka nie będzie większa, nawet przy Stretch.
ActualWidth, ActualHeightTylko do odczytu w C#: rzeczywisty rozmiar po ułożeniu okna.

Lepiej MinWidth niż Width

Przy stałej szerokości dłuższy napis albo większa czcionka zostaną ucięte. MinWidth daje równe przyciski przy krótkich napisach, a przy długich pozwala im urosnąć.

TEORIA

Widoczność i dostępność

Visibility — trzy wartości, nie dwie

WartośćCzy widać?Czy zajmuje miejsce?
Visibletaktak
Hiddennietak — zostaje pusta dziura
Collapsednienie — reszta przesuwa się na jej miejsce
Visible
Pierwszy
Drugi
Trzeci
Hidden
Pierwszy
Trzeci
Collapsed
Pierwszy
Trzeci

ten sam panel — zmienia się tylko Visibility drugiego przycisku

IsEnabled, Opacity, ToolTip

IsEnabled="False" wyszarza kontrolkę i blokuje ją — przycisku nie da się kliknąć. Ustawione na panelu blokuje cały panel z zawartością. Opacity (lekcja 02) tylko zmienia przezroczystość — kontrolka z Opacity="0" jest niewidoczna, ale nadal działa. Do ukrywania używaj Visibility. ToolTip="…" pokazuje dymek z podpowiedzią po najechaniu myszą.

TEORIA

Dziedziczenie czcionki

Właściwości czcionki (FontSize, FontFamily, FontWeight) i Foreground są dziedziczone: ustawione na oknie przechodzą na wszystkie elementy w środku, które nie mają własnej wartości. Kontrolka z własnym FontSize zachowa swoją wartość.

MainWindow.xaml
<Window … FontSize="16">
    <StackPanel Margin="15">
        <TextBlock Text="Ma rozmiar 16 — odziedziczył po oknie"/>
        <Button Content="Też 16"/>
        <TextBlock Text="Ma własne 24" FontSize="24"/>
    </StackPanel>
</Window>

Background nie jest dziedziczony. Przyciski mają tło i kolor tekstu ze stylu systemu, więc kolor okna ich nie zmienia — ale czcionkę po oknie dziedziczą.

TEORIA

Zmiana z kodu C#

XAMLC#
Margin="0,10,0,0"Opis.Margin = new Thickness(0, 10, 0, 0);
Padding="8"Kup.Padding = new Thickness(8);
Visibility="Collapsed"Opis.Visibility = Visibility.Collapsed;
HorizontalAlignment="Center"Kup.HorizontalAlignment = HorizontalAlignment.Center;
IsEnabled="False"Kup.IsEnabled = false;
FontSize="18"Opis.FontSize = 18;
Width="Auto" (brak stałej szerokości)Kup.Width = double.NaN;

Odczyt działa tak samo: if (Opis.Visibility == Visibility.Visible). Klasy Thickness, Visibility i HorizontalAlignment są w przestrzeni nazw System.Windows, dołączonej w każdym pliku okna.

PRZYKŁAD

Karta produktu w sklepie

Karta słuchawek: nazwa, cena, opis i przyciski. Ukryj opis zwija opis, a karta robi się krótsza. A+ i A− zmieniają czcionkę okna. Dodaj do koszyka blokuje się po kliknięciu, żeby nie dodać produktu dwa razy.

Karta produktu–□✕
Słuchawki X200
199 zł
Bezprzewodowe słuchawki z redukcją szumów. Do 30 godzin pracy na baterii, ładowanie przez USB-C.
Ukryj opis
A+
A−
Dodaj do koszyka
Karta produktu–□✕
Słuchawki X200
199 zł
Pokaż opis
A+
A−
W koszyku
Produkt dodany do koszyka.

po lewej stan startowy, po prawej — po zwinięciu opisu i dodaniu do koszyka

MainWindow.xaml — pełny plik
<Window x:Class="Lekcja05.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Karta produktu" Height="430" Width="420"
        WindowStartupLocation="CenterScreen">

    <StackPanel Margin="20">
        <TextBlock Text="Słuchawki X200" FontSize="22" FontWeight="Bold"/>
        <TextBlock Text="199 zł" FontSize="18" Foreground="Green" Margin="0,4,0,10"/>

        <TextBlock x:Name="Opis" TextWrapping="Wrap" Margin="0,0,0,10"
                   Text="Bezprzewodowe słuchawki z redukcją szumów. Do 30 godzin pracy na baterii, ładowanie przez USB-C."/>

        <StackPanel Orientation="Horizontal">
            <Button x:Name="OpisPrzycisk" Content="Ukryj opis" Padding="8,4" Margin="0,0,8,0" Click="Opis_Click"/>
            <Button Content="A+" Padding="8,4" Margin="0,0,8,0" Click="Wieksza_Click" ToolTip="Większa czcionka"/>
            <Button Content="A−" Padding="8,4" Click="Mniejsza_Click" ToolTip="Mniejsza czcionka"/>
        </StackPanel>

        <Button x:Name="Kup" Content="Dodaj do koszyka"
                Margin="0,15,0,0" Padding="10,6"
                Background="Orange" ToolTip="Dodaje produkt do koszyka"
                Click="Kup_Click"/>

        <TextBlock x:Name="Status" Margin="0,10,0,0"/>
    </StackPanel>
</Window>
MainWindow.xaml.cs — pełny plik
using System.Windows;

namespace Lekcja05;

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

    private void Opis_Click(object sender, RoutedEventArgs e)
    {
        if (Opis.Visibility == Visibility.Visible)
        {
            Opis.Visibility = Visibility.Collapsed;   // znika i nie zajmuje miejsca
            OpisPrzycisk.Content = "Pokaż opis";
        }
        else
        {
            Opis.Visibility = Visibility.Visible;
            OpisPrzycisk.Content = "Ukryj opis";
        }
    }

    // FontSize okna dziedziczą wszystkie elementy, które nie mają własnego FontSize
    private void Wieksza_Click(object sender, RoutedEventArgs e)
    {
        if (FontSize < 24)
        {
            FontSize += 2;
        }
    }

    private void Mniejsza_Click(object sender, RoutedEventArgs e)
    {
        if (FontSize > 10)
        {
            FontSize -= 2;
        }
    }

    private void Kup_Click(object sender, RoutedEventArgs e)
    {
        Kup.IsEnabled = false;
        Kup.Content = "W koszyku";
        Status.Text = "Produkt dodany do koszyka.";
    }
}

Co dzieje się po kolei

  • Cena ma Margin="0,4,0,10": mały odstęp od nazwy i większy od opisu — wizualnie należy do nazwy.
  • Małe przyciski mają Padding="8,4": 8 po bokach, 4 u góry i dołu, więc tekst nie przykleja się do ramki.
  • Przycisk koszyka nie ma HorizontalAlignment — domyślne Stretch rozciąga go na całą szerokość, jak w sklepach internetowych.
  • Opis_Click sprawdza aktualną widoczność i ustawia przeciwną. Z jednego przycisku powstaje przełącznik, a jego napis zawsze mówi, co się stanie po kliknięciu.
  • Collapsed, a nie Hidden: po zwinięciu opisu przyciski przesuwają się w górę.
  • FontSize += 2; bez nazwy przed kropką zmienia czcionkę okna. Opis, status i przyciski ją dziedziczą; nazwa i cena mają własne FontSize, więc się nie zmieniają.
  • Warunki FontSize < 24 i FontSize > 10 nie pozwalają rozsypać układu zbyt dużą albo nieczytelną czcionką.
  • Kup.IsEnabled = false; zostawia przycisk widoczny, ale wyszarzony — użytkownik widzi, że akcja została wykonana.

Sprawdź trzy rzeczy

  1. Zmień w Opis_Click Visibility.Collapsed na Visibility.Hidden. Opis zniknie, ale zostanie po nim pusta przestrzeń.
  2. Kliknij kilka razy A+. Nazwa i cena się nie zmieniają — usuń im FontSize i sprawdź ponownie.
  3. Zamiast IsEnabled = false ustaw Kup.Opacity = 0;. Przycisk zniknie, ale kliknięcie w jego miejscu nadal go uruchomi.
ELEMENTY WBUDOWANE

Zestawienie elementów

ElementZnaczenieUwagi
Margin, Paddingodstęp zewnętrzny i wewnętrzny1, 2 albo 4 liczby. W C#: new Thickness(…).
HorizontalAlignment, VerticalAlignmentpołożenie w obszarze od paneluDomyślnie Stretch.
Width, MinWidth, MaxWidthszerokość stała, minimalna, maksymalnaAnalogicznie Height. double.NaN = brak stałej wartości.
VisibilityVisible, Hidden, CollapsedTylko Collapsed zwalnia miejsce.
IsEnabledczy kontrolkę można obsługiwaćNa panelu — dla całej zawartości.
Opacityprzezroczystość 0–1Przy 0 kontrolka nadal działa.
ToolTippodpowiedź po najechaniuDla przycisków z krótkim napisem.
FontSize, Foregroundczcionka i kolor tekstuDziedziczone po oknie; własna wartość ma pierwszeństwo.
FontSize += 2; w klasie oknazmiana czcionki oknaDziała na wszystkie elementy bez własnego rozmiaru.
CZĘSTE BŁĘDY

Zanim utkniesz

Zapis lub sytuacjaProblem
Opis.Visibility = false;CS0029 — Visibility ma trzy wartości, to nie bool. Użyj Visibility.Collapsed.
Opis.Margin = "0,10,0,0";CS0029 — w C# margines to new Thickness(0, 10, 0, 0).
<StackPanel Padding="10">The property 'Padding’ was not found in type 'StackPanel’. Odsuń zawartość marginesem panelu.
Margin="10,5,10"Trzy liczby to błąd — dozwolone 1, 2 albo 4.
Width="200" HorizontalAlignment="Stretch"Width wygrywa — przycisk się nie rozciągnie.
Opacity="0" do ukrycia przyciskuPrzycisk jest niewidoczny, ale da się go kliknąć.
Hidden tam, gdzie miało zniknąć miejsceZostaje pusta przestrzeń. Do zwijania służy Collapsed.
VerticalAlignment="Bottom" w pionowym StackPanelNie działa — panel nie daje dodatkowej wysokości. Do takich układów służy Grid (lekcja 09).
ZADANIA

Zadania

Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.

ZAD 1Okno logowania według specyfikacji★☆☆

Odtwórz układ według opisu, jak w arkuszu egzaminacyjnym: okno 360 × 240, zawartość odsunięta o 20 od krawędzi; nagłówek „Logowanie do e-dziennika” rozmiar 18, pogrubiony, wyśrodkowany, z odstępem 15 pod spodem; dwa napisy informacyjne (szare); na dole dwa przyciski Anuluj i Zaloguj obok siebie, dosunięte do prawej krawędzi, każdy o minimalnej szerokości 90, z odstępem 8 między nimi i wewnętrznym odstępem 10 w poziomie i 4 w pionie. Zaloguj ma podpowiedź „Wymaga konta szkolnego”.

pokaż wskazówkę
  • Dwa przyciski obok siebie: poziomy StackPanel. Do prawej dosuniesz cały panel, a nie pojedyncze przyciski.
  • „10 w poziomie i 4 w pionie” to dwuliczbowy zapis Padding.
ZAD 2Zagadka ze spoilerem★☆☆

Okno z zagadką: „Co ma klawisze, ale nie otwiera drzwi?”. Pod nią odpowiedź „Klawiatura” (na starcie zwinięta) i przycisk Pokaż odpowiedź, który odsłania odpowiedź i zmienia swój napis na Ukryj odpowiedź — i odwrotnie. Dodaj licznik „Podejrzano: 3 razy”, który rośnie tylko przy odsłanianiu.

pokaż wskazówkę
  • Stan startowy ustaw w XAML: Visibility="Collapsed".
  • Licznik rośnie w tej gałęzi if, która pokazuje odpowiedź.
ZAD 3Hidden czy Collapsed?★☆☆

Ułóż trzy napisy z różnym tłem (czerwone, zielone, niebieskie; z wewnętrznym odstępem 10), a pod nimi przyciski Visible, Hidden, Collapsed, które zmieniają widoczność środkowego napisu. Każdy przycisk staje się nieaktywny, gdy jego wartość jest aktualnie ustawiona. W komentarzu opisz, co dzieje się z niebieskim napisem w każdym przypadku.

pokaż wskazówkę
  • Kolor tła napisu ustawisz w XAML atrybutem Background z nazwą koloru.
  • Najprościej napisać metodę, która po każdej zmianie ustawia IsEnabled wszystkich trzech przycisków na podstawie aktualnej Visibility.
ZAD 4Akceptacja regulaminu★★☆

Okno instalatora: nagłówek, zawijany tekst regulaminu (kilka zdań), przycisk Przeczytałem regulamin i przycisk Dalej, który na starcie jest nieaktywny. Po kliknięciu pierwszego przycisku: Dalej staje się aktywny, regulamin robi się półprzezroczysty (0.5), a przycisk „Przeczytałem…” znika bez zostawiania miejsca. Dalej chowa regulamin i wszystkie przyciski, a pokazuje (wcześniej zwinięty) napis „Instalacja zakończona”.

pokaż wskazówkę
  • Elementy do schowania razem możesz włożyć w jeden panel z nazwą i chować tylko panel.
  • Przycisk może ukryć sam siebie — przez nazwę albo przez (Button)sender.
ZAD 5Wyrównanie z kodu★★☆

Okno ma przycisk Złap mnie o szerokości 120 i pod nim cztery przyciski: Do lewej, Na środek, Do prawej, Rozciągnij. Każdy ustawia odpowiednie wyrównanie przycisku „Złap mnie”, a napis pod spodem pokazuje jego aktualną szerokość, np. „Szerokość: 120”. Przy „Rozciągnij” przycisk ma naprawdę zająć całą szerokość. Wszystkie cztery przyciski obsługuje jedna metoda.

pokaż wskazówkę
  • Przy rozciąganiu trzeba zdjąć stałą szerokość: double.NaN; przy pozostałych — przywrócić 120.
  • Rzeczywistą szerokość poda ActualWidth — ale aktualizuje się dopiero po ułożeniu okna, więc przy „Rozciągnij” odczytaj ją przy kolejnym kliknięciu albo pokaż „Szerokość: cała dostępna”.
ZAD 6Ustawienia dostępności★★★

Okno z artykułem (tytuł i trzy akapity) i paskiem przycisków: A−, A+, Tryb skupienia. Wymagania:

  • czcionka całego tekstu zmienia się o 2 w zakresie 10–28; przycisk, który na granicy zakresu nie może już działać, jest nieaktywny; napis „Rozmiar: 14” pokazuje aktualną wartość;
  • Tryb skupienia chowa tytuł i wszystkie akapity poza pierwszym (bez zostawiania miejsca), zwiększa odstęp między liniami przez marginesy akapitów i zmienia napis przycisku na Pokaż wszystko; ponowne kliknięcie przywraca stan;
  • tytuł ma własny rozmiar czcionki i nie zmienia się przy A−/A+ — w komentarzu wyjaśnij dlaczego.
pokaż wskazówkę
  • Zmieniaj FontSize okna — akapity bez własnego rozmiaru odziedziczą go same.
  • Napisz jedną metodę, która po każdej zmianie ustawia napis z rozmiarem i IsEnabled obu przycisków.
  • Stan trybu trzymaj w polu bool.
PODSUMOWANIE

Co trzeba zapamiętać

  • Margin — odstęp na zewnątrz, Padding — w środku. Zapis: 1, 2 albo 4 liczby (lewo, góra, prawo, dół).
  • Wyrównanie domyślnie Stretch; Width ma pierwszeństwo przed rozciąganiem.
  • MinWidth / MaxWidth ograniczają rozmiar, nie blokując dopasowania do treści.
  • Hidden zostawia miejsce, Collapsed — nie. Opacity="0" nie wyłącza kontrolki.
  • IsEnabled="False" blokuje kontrolkę, a na panelu — całą zawartość.
  • Czcionka i Foreground są dziedziczone po oknie; własna wartość kontrolki ma pierwszeństwo.
  • W C#: new Thickness(…), Visibility.Collapsed, HorizontalAlignment.Right, double.NaN.

Dokumentacja: Microsoft Learn — klasa FrameworkElement, wyrównanie, marginesy i odstępy.

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