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ą.
Czego się dziś nauczysz
- Odróżnisz
MarginodPaddingi zapiszesz je jedną, dwiema lub czterema liczbami. - Ustawisz położenie kontrolki przez
HorizontalAlignmentiVerticalAlignmenti przewidzisz efekt wStackPanel. - Ograniczysz rozmiar przez
Width,MinWidth,MaxWidth. - Wyjaśnisz różnicę między
HiddenaCollapsed. - Zablokujesz kontrolkę przez
IsEnabledi dodasz podpowiedźToolTip. - Zmienisz te właściwości z C# i wykorzystasz dziedziczenie czcionki po oknie.
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.
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).
przycisk: przerywana linia to granica marginesu, ramka to krawędź przycisku
| Zapis | Znaczenie | Kiedy |
|---|---|---|
Margin="10" | 10 ze wszystkich stron | ró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.
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ć:
<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>
Stretch to wartość domyślna — dlatego przyciski w pionowym panelu rozciągają się na całą szerokość
| Właściwość | Wartości | Uwagi |
|---|---|---|
HorizontalAlignment | Left, Center, Right, Stretch | Domyślnie Stretch. |
VerticalAlignment | Top, Center, Bottom, Stretch | W pionowym StackPanel nie ma efektu — panel daje kontrolce tyle wysokości, ile potrzebuje. |
HorizontalContentAlignment | jak wyżej | Wyrównanie zawartości wewnątrz kontrolki, np. tekstu w szerokim przycisku. |
Rozmiar: stały, minimalny, maksymalny
| Właściwość | Co robi |
|---|---|
Width, Height | Stały rozmiar. Ma pierwszeństwo przed Stretch. |
MinWidth, MinHeight | Kontrolka nie będzie mniejsza, nawet przy krótkim tekście. |
MaxWidth, MaxHeight | Kontrolka nie będzie większa, nawet przy Stretch. |
ActualWidth, ActualHeight | Tylko 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ąć.
Widoczność i dostępność
Visibility — trzy wartości, nie dwie
| Wartość | Czy widać? | Czy zajmuje miejsce? |
|---|---|---|
Visible | tak | tak |
Hidden | nie | tak — zostaje pusta dziura |
Collapsed | nie | nie — reszta przesuwa się na jej miejsce |
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ą.
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ść.
<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ą.
Zmiana z kodu C#
| XAML | C# |
|---|---|
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.
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.
po lewej stan startowy, po prawej — po zwinięciu opisu i dodaniu do koszyka
<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>
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ślneStretchrozciąga go na całą szerokość, jak w sklepach internetowych. Opis_Clicksprawdza 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 nieHidden: 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łasneFontSize, więc się nie zmieniają.- Warunki
FontSize < 24iFontSize > 10nie 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
- Zmień w
Opis_ClickVisibility.CollapsednaVisibility.Hidden. Opis zniknie, ale zostanie po nim pusta przestrzeń. - Kliknij kilka razy A+. Nazwa i cena się nie zmieniają — usuń im
FontSizei sprawdź ponownie. - Zamiast
IsEnabled = falseustawKup.Opacity = 0;. Przycisk zniknie, ale kliknięcie w jego miejscu nadal go uruchomi.
Zestawienie elementów
| Element | Znaczenie | Uwagi |
|---|---|---|
Margin, Padding | odstęp zewnętrzny i wewnętrzny | 1, 2 albo 4 liczby. W C#: new Thickness(…). |
HorizontalAlignment, VerticalAlignment | położenie w obszarze od panelu | Domyślnie Stretch. |
Width, MinWidth, MaxWidth | szerokość stała, minimalna, maksymalna | Analogicznie Height. double.NaN = brak stałej wartości. |
Visibility | Visible, Hidden, Collapsed | Tylko Collapsed zwalnia miejsce. |
IsEnabled | czy kontrolkę można obsługiwać | Na panelu — dla całej zawartości. |
Opacity | przezroczystość 0–1 | Przy 0 kontrolka nadal działa. |
ToolTip | podpowiedź po najechaniu | Dla przycisków z krótkim napisem. |
FontSize, Foreground | czcionka i kolor tekstu | Dziedziczone po oknie; własna wartość ma pierwszeństwo. |
FontSize += 2; w klasie okna | zmiana czcionki okna | Działa na wszystkie elementy bez własnego rozmiaru. |
Zanim utkniesz
| Zapis lub sytuacja | Problem |
|---|---|
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 przycisku | Przycisk jest niewidoczny, ale da się go kliknąć. |
Hidden tam, gdzie miało zniknąć miejsce | Zostaje pusta przestrzeń. Do zwijania służy Collapsed. |
VerticalAlignment="Bottom" w pionowym StackPanel | Nie działa — panel nie daje dodatkowej wysokości. Do takich układów służy Grid (lekcja 09). |
Zadania
Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
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.
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ź.
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
Backgroundz nazwą koloru. - Najprościej napisać metodę, która po każdej zmianie ustawia
IsEnabledwszystkich trzech przycisków na podstawie aktualnejVisibility.
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.
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”.
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
FontSizeokna — akapity bez własnego rozmiaru odziedziczą go same. - Napisz jedną metodę, która po każdej zmianie ustawia napis z rozmiarem i
IsEnabledobu przycisków. - Stan trybu trzymaj w polu
bool.
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;Widthma pierwszeństwo przed rozciąganiem. MinWidth/MaxWidthograniczają rozmiar, nie blokując dopasowania do treści.Hiddenzostawia miejsce,Collapsed— nie.Opacity="0"nie wyłącza kontrolki.IsEnabled="False"blokuje kontrolkę, a na panelu — całą zawartość.- Czcionka i
Foregroundsą 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.