DockPanel — paski przy krawędziach
Otwórz Notatnik, przeglądarkę albo Visual Studio: u góry pasek z przyciskami, na dole pasek stanu, z boku panel, a w środku główna treść, która zajmuje resztę okna. Ten układ ma swój panel — DockPanel. Przyklejasz kontrolki do krawędzi, a ostatnia wypełnia to, co zostało. To ostatni panel układu w tym bloku: po nim umiesz zbudować okno każdej typowej aplikacji desktopowej.
Czego się dziś nauczysz
- Przykleisz kontrolki do krawędzi okna właściwością
DockPanel.Dock. - Przewidzisz, jak kolejność kontrolek w XAML zmienia układ.
- Wyjaśnisz działanie
LastChildFilli umieścisz główną treść jako ostatnie dziecko. - Zbudujesz klasyczne okno aplikacji: pasek przycisków, pasek stanu, panel boczny i treść.
- Dobierzesz panel do okna:
DockPanel,Gridalbo oba naraz.
Dokowanie do krawędzi
Każde dziecko DockPanel dostaje właściwość dołączoną DockPanel.Dock — jak Grid.Row w lekcji 09 — z jedną z czterech wartości: Top, Bottom, Left, Right.
<DockPanel>
<Border DockPanel.Dock="Top" Background="SteelBlue" Padding="8">
<TextBlock Text="Pasek u góry" Foreground="White"/>
</Border>
<Border DockPanel.Dock="Bottom" Background="LightGray" Padding="4">
<TextBlock Text="Pasek stanu"/>
</Border>
<Border DockPanel.Dock="Left" Background="LightBlue" Width="120" Padding="8">
<TextBlock Text="Panel boczny"/>
</Border>
<TextBox Text="Treść — wypełnia resztę"/>
</DockPanel>
powiększ okno — paski zachowują grubość, rośnie treść
Kontrolka przyklejona do góry lub dołu dostaje pełną dostępną szerokość i tyle wysokości, ile potrzebuje. Przyklejona do boku — pełną dostępną wysokość i tyle szerokości, ile potrzebuje (albo Width). Bez DockPanel.Dock kontrolka jest dokowana do lewej, bo Left to wartość domyślna.
Kolejność ma znaczenie
DockPanel rozmieszcza dzieci po kolei, w kolejności z XAML. Każda kontrolka zabiera pas przy swojej krawędzi z tego miejsca, które jeszcze zostało. Kto pierwszy, ten dostaje pełną długość krawędzi:
najpierw Top: pasek nad panelem bocznym
najpierw Left: panel boczny na całą wysokość
Zasada praktyczna: najpierw paski na całą szerokość (Top, Bottom), potem panele boczne, na końcu treść.
LastChildFill
Domyślnie LastChildFill="True": ostatnie dziecko nie jest dokowane, tylko wypełnia całe pozostałe miejsce — jego DockPanel.Dock jest pomijane. Dlatego główną treść zawsze piszesz na końcu.
<!-- rząd przycisków przyklejony do prawej, bez rozciągania ostatniego -->
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Right" Content="Anuluj" Width="80"/>
<Button DockPanel.Dock="Right" Content="OK" Width="80" Margin="0,0,6,0"/>
</DockPanel>
Z LastChildFill="False" ostatnie dziecko też jest dokowane, a pośrodku zostaje puste miejsce. Zwróć uwagę: dwa przyciski Right stają od prawej — pierwszy w pliku jest najbardziej z prawej.
DockPanel czy Grid?
To samo okno zbudujesz w Grid z wierszami Auto, *, Auto i kolumnami. DockPanel jest krótszy i czytelniejszy, gdy układ to „paski przy krawędziach + treść”. Grid wygrywa, gdy elementy trzeba wyrównać w kolumnach (formularz) albo podzielić miejsce w proporcjach. W praktyce łączy się oba: DockPanel dla całego okna, a w środku Grid z formularzem.
| Potrzeba | Wybór |
|---|---|
| pasek u góry, pasek stanu, panel boczny, treść | DockPanel |
| etykiety i pola w równych kolumnach | Grid |
| dwie kolumny w proporcji 1 : 3 | Grid |
| przyciski dosunięte do prawej w jednym rzędzie | StackPanel z HorizontalAlignment="Right" albo DockPanel z LastChildFill="False" |
Notatnik szkolny
Prosty notatnik w klasycznym układzie: u góry pasek z przyciskami, na dole pasek stanu z liczbą znaków i słów, po lewej panel szablonów, a w środku duże pole tekstowe. Szablon i data wstawiają się w miejscu kursora, a przyciski A+ i A− zmieniają rozmiar czcionki.
Najważniejsze pojęcia:
– DockPanel.Dock
– LastChildFill
Zadanie domowe: zad 3 i 4, termin 08.10.2026
po wstawieniu szablonu „Notatka z lekcji” i uzupełnieniu go
<Window x:Class="Lekcja13.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Notatnik szkolny" Height="420" Width="620"
MinWidth="480" MinHeight="300"
WindowStartupLocation="CenterScreen">
<DockPanel>
<!-- 1. Pasek u góry: na całą szerokość okna -->
<Border DockPanel.Dock="Top" Background="#FF374151" Padding="6">
<StackPanel Orientation="Horizontal">
<Button Content="Nowy" Width="80" Margin="0,0,6,0" Click="Nowy_Click"/>
<Button Content="Wstaw datę" Width="90" Margin="0,0,6,0" Click="Data_Click"/>
<Button Content="A+" Width="36" Margin="0,0,6,0" Click="Wieksza_Click"/>
<Button Content="A−" Width="36" Click="Mniejsza_Click"/>
</StackPanel>
</Border>
<!-- 2. Pasek stanu na dole: też na całą szerokość -->
<Border DockPanel.Dock="Bottom" Background="#FFE5E7EB" Padding="8,3">
<TextBlock x:Name="Stan" Text="Znaków: 0 | Słów: 0 | Rozmiar: 14"/>
</Border>
<!-- 3. Panel szablonów po lewej: między paskami -->
<Border DockPanel.Dock="Left" Width="160" Background="#FFF3F4F6"
BorderBrush="LightGray" BorderThickness="0,0,1,0" Padding="8">
<StackPanel>
<TextBlock Text="Szablony" FontWeight="Bold" Margin="0,0,0,6"/>
<Button Content="Usprawiedliwienie" Margin="0,0,0,4" Click="Szablon_Click"
Tag="Proszę o usprawiedliwienie nieobecności mojego dziecka w dniu …
Powód: …
Podpis rodzica: …"/>
<Button Content="Notatka z lekcji" Margin="0,0,0,4" Click="Szablon_Click"
Tag="Temat: …
Najważniejsze pojęcia:
- …
Zadanie domowe: …"/>
<Button Content="Lista zakupów" Click="Szablon_Click"
Tag="Do kupienia:
- zeszyt
- długopis
- …"/>
</StackPanel>
</Border>
<!-- 4. Ostatnie dziecko wypełnia całą resztę (LastChildFill) -->
<TextBox x:Name="Tekst" AcceptsReturn="True" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" FontSize="14" Padding="6"
BorderThickness="0" TextChanged="Tekst_TextChanged"/>
</DockPanel>
</Window>
using System.Windows;
using System.Windows.Controls;
namespace Lekcja13;
public partial class MainWindow : Window
{
private readonly char[] separatory = { ' ', '\n', '\r', '\t' };
public MainWindow()
{
InitializeComponent();
}
private void Nowy_Click(object sender, RoutedEventArgs e)
{
if (Tekst.Text != "")
{
MessageBoxResult odp = MessageBox.Show("Wyczyścić notatkę?", "Nowy",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (odp != MessageBoxResult.Yes)
{
return;
}
}
Tekst.Clear();
Tekst.Focus();
}
private void Data_Click(object sender, RoutedEventArgs e)
{
Wstaw(DateTime.Now.ToString("dd.MM.yyyy"));
}
private void Szablon_Click(object sender, RoutedEventArgs e)
{
Button przycisk = (Button)sender;
Wstaw((string)przycisk.Tag);
}
private void Wieksza_Click(object sender, RoutedEventArgs e)
{
if (Tekst.FontSize < 28)
{
Tekst.FontSize += 2;
PokazStan();
}
}
private void Mniejsza_Click(object sender, RoutedEventArgs e)
{
if (Tekst.FontSize > 10)
{
Tekst.FontSize -= 2;
PokazStan();
}
}
private void Tekst_TextChanged(object sender, TextChangedEventArgs e)
{
PokazStan();
}
// Wstawia tekst w miejscu kursora (albo zamiast zaznaczenia)
private void Wstaw(string wstawka)
{
Tekst.SelectedText = wstawka;
Tekst.SelectionLength = 0;
Tekst.CaretIndex = Tekst.SelectionStart + wstawka.Length; // kursor za wstawką
Tekst.Focus();
}
private void PokazStan()
{
int slowa = Tekst.Text.Split(separatory, StringSplitOptions.RemoveEmptyEntries).Length;
Stan.Text = $"Znaków: {Tekst.Text.Length} | Słów: {slowa} | Rozmiar: {Tekst.FontSize}";
}
}
Co dzieje się po kolei
- Kolejność w
DockPanel: góra, dół, lewa, treść. Paski górny i dolny są pierwsze, więc mają pełną szerokość okna; panel szablonów mieści się między nimi. - Pole
Tekstnie maDockPanel.Dock— jako ostatnie dziecko wypełnia resztę okna i rośnie razem z nim. - Panel szablonów to
BorderzWidth="160"i linią tylko po prawej stronie (BorderThickness="0,0,1,0"), która oddziela go od treści. - Treść szablonów jest w
Tagprzycisków.
to zapis znaku nowej linii w atrybucie XAML — wewnątrz cudzysłowu nie można po prostu nacisnąć Enter. - Wszystkie szablony obsługuje jedna metoda
Szablon_Click, która odczytujeTagklikniętego przycisku. WstawużywaSelectedText: przypisanie wstawia tekst w miejscu kursora, a jeśli coś było zaznaczone — zastępuje zaznaczenie. Potem kursor jest przesuwany za wstawkę przezCaretIndex.- Liczba słów to liczba kawałków po podziale tekstu na spacjach, tabulatorach i znakach nowej linii;
RemoveEmptyEntriespomija puste kawałki między dwiema spacjami. - Nowy pyta o potwierdzenie tylko wtedy, gdy notatka nie jest pusta.
Sprawdź trzy rzeczy
- Przenieś w XAML panel szablonów (
BorderzLeft) na samą góręDockPanel. Panel zajmie całą wysokość okna, a paski skrócą się do prawej części. - Przenieś
TextBoxprzed pasek stanu. Teraz ostatnim dzieckiem jest pasek stanu — wypełni on środek okna, a notatka przyklei się do lewej. - Zaznacz myszą słowo w notatce i kliknij Wstaw datę. Data zastąpi zaznaczone słowo.
Zestawienie elementów
| Element | Typ / wartości | Co robi |
|---|---|---|
DockPanel.Dock | Top, Bottom, Left, Right | Właściwość dołączona — do której krawędzi przykleić kontrolkę. Domyślnie Left. |
LastChildFill | bool | True (domyślnie) — ostatnie dziecko wypełnia resztę. |
TextBox.SelectedText | string | Zaznaczony tekst; przypisanie wstawia tekst w miejscu kursora. |
CaretIndex | int | Pozycja kursora w polu (liczba znaków przed kursorem). |
SelectionStart, SelectionLength | int | Początek i długość zaznaczenia. |
Split(tablicaZnakow, StringSplitOptions.RemoveEmptyEntries) | string[] | Dzieli tekst na kawałki według kilku separatorów, pomija puste. |

 | XAML | Znak nowej linii w wartości atrybutu. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
| treść w środku listy dzieci, a pasek stanu na końcu | Pasek stanu wypełnia środek okna. Treść zawsze jako ostatnie dziecko. |
Dock="Top" | Błąd XAML — potrzebny przedrostek: DockPanel.Dock="Top". |
DockPanel.Dock="Bottom" przy ostatnim dziecku | Ignorowane przy LastChildFill="True" — kontrolka i tak wypełnia resztę. |
| panel boczny przed paskami | Panel na pełną wysokość, paski krótsze. Najpierw Top/Bottom. |
dwa przyciski Right w kolejności „OK”, „Anuluj” | Na ekranie odwrotnie: „Anuluj OK” — pierwszy w pliku jest najbardziej z prawej. |
panel Left bez Width z długim tekstem | Panel jest tak szeroki jak najdłuższy tekst i może zabrać większość okna. |
nowa linia wpisana Enter w atrybucie Tag | XAML zamienia ją na spację. Użyj 
. |
Zadania
Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Główny układ okna buduj na DockPanel; w jego częściach możesz używać wszystkich poznanych paneli. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
Układ odtwarzacza: u góry ciemny pasek z nazwą programu, po lewej playlista z 5 przyciskami utworów (szerokość 180), na dole pasek z przyciskami ⏮, ▶, ⏭ wyśrodkowanymi w poziomie, a w środku duży napis z tytułem i wykonawcą. Kliknięcie utworu na playliście pokazuje go w środku, a ⏮/⏭ przechodzą do poprzedniego/następnego (po ostatnim jest pierwszy). ▶ zmienia się na ⏸ i z powrotem, a napis w środku pokazuje „gra” albo „pauza”.
pokaż wskazówkę
- Tytuły i wykonawców zapisz w dwóch tablicach, a numer bieżącego utworu w polu klasy. Numer utworu przycisku playlisty możesz trzymać w
Tag. - Następny utwór „w kółko”:
(numer + 1) % liczbaUtworow.
Okno podzielone na dwie równe kolumny (Grid). W każdej kolumnie DockPanel z tymi samymi czterema kolorowymi ramkami z napisami: „Top”, „Left”, „Bottom” i „Treść”, ale w innej kolejności. Pod spodem w każdej kolumnie przycisk Pokaż kolejność, który w MessageBox wypisuje kolejność dzieci panelu (odczytaną z kodu, nie wpisaną na sztywno). W komentarzu w XAML opisz, dlaczego układy się różnią.
pokaż wskazówkę
- Napisy ramek odczytasz w
foreach (Border b in Panel.Children)i rzutowaniu(TextBlock)b.Child. - Najpierw przewiduj na kartce, potem uruchom — to cały sens zadania.
Po lewej lista pięciu przepisów (przyciski), u góry nagłówek z nazwą bieżącego przepisu i czasem przygotowania („Naleśniki · 30 min”), w środku przewijany tekst przepisu (składniki i kroki), na dole pasek z przyciskami ◀ Poprzedni i Następny ▶ po bokach i napisem „Przepis 2 z 5” pośrodku. Na pierwszym przepisie przycisk „Poprzedni” jest nieaktywny, na ostatnim — „Następny”.
pokaż wskazówkę
- Dolny pasek to też
DockPanel: przyciskLeft, przyciskRight, napis jako ostatnie dziecko zTextAlignment="Center". - Wszystko, co zależy od numeru przepisu, ustawiaj w jednej metodzie
PokazPrzepis(int numer).
U góry pasek z przyciskami WIELKIE, małe, Odwróć, Bez polskich znaków. Pod paskiem wielowierszowe pole wejściowe o wysokości 120, a w środku (reszta okna) pole wyniku tylko do odczytu. Na dole pasek stanu: „Wejście: 54 zn. | Wynik: 54 zn. | Ostatnia operacja: Odwróć”. „Bez polskich znaków” zamienia ą→a, ć→c, ę→e, ł→l, ń→n, ó→o, ś→s, ź→z, ż→z (także wielkie litery).
pokaż wskazówkę
- Pole wejściowe to drugie dziecko z
DockPanel.Dock="Top"— ustawi się pod paskiem przycisków. - Odwrócenie: zamień tekst na tablicę znaków (
ToCharArray()), użyjArray.Reversei zbuduj napis przeznew string(tablica). - Polskie znaki: dwa napisy
"ąćęłńóśźżĄĆĘŁŃÓŚŹŻ"i"acelnoszzACELNOSZZ"oraz pętla zIndexOf.
Po lewej menu: Komputery, Drukarki, Zgłoszenia. W środku trzy różne widoki ułożone w jednej komórce Grid, z których widoczny jest zawsze jeden: siatka 16 stanowisk (zielone — sprawne, czerwone — w naprawie; kliknięcie zmienia stan), lista dwóch drukarek z poziomem tonera i lista zgłoszeń. U góry nagłówek z nazwą bieżącego widoku, na dole pasek stanu „Sprawne: 14 / 16 · ostatnia zmiana 10:42”. Przycisk menu bieżącego widoku jest wyróżniony pogrubieniem.
pokaż wskazówkę
- Trzy panele bez
Grid.Roww jednej komórce nakładają się — przełączasz je przezVisibility(lekcja 05). - Stanowiska utwórz w pętli w
UniformGrid4 × 4, stan zapisuj wTag.
Edytor ogłoszenia na szkolny korytarz:
- u góry pasek z czterema kolorowymi przyciskami motywów (tło i kolor tekstu plakatu, np. żółty z czarnym, granatowy z białym) — dane motywu w
Tag; - po lewej formularz w
Grid(szerokość 240): Tytuł, Data, Miejsce, Treść (wielowierszowa, rośnie z oknem); - w środku podgląd plakatu:
Borderz zaokrąglonymi rogami, dużym tytułem, datą i miejscem w jednej linii oraz treścią — zmieniany na żywo przy każdej zmianie pól; - na dole pasek stanu: „Treść: 87 / 200 znaków”, który robi się czerwony powyżej 160 znaków, i przycisk Drukuj dosunięty do prawej, nieaktywny, dopóki tytuł jest pusty. „Drukuj” pokazuje
MessageBoxz pełnym tekstem plakatu.
pokaż wskazówkę
- Kolejność w głównym
DockPanel: góra, dół, lewa, podgląd. Dolny pasek to kolejnyDockPanelz przyciskiemRighti napisem jako ostatnim dzieckiem. - Wszystkie pola mogą mieć jedną metodę
TextChanged, która przepisuje cały podgląd. - W
Tagprzycisku motywu zapisz jego numer, a pędzle tła i tekstu dobierz wswitch. Bieżący motyw pamiętaj w polu klasy.
Co trzeba zapamiętać
DockPanel.Dockprzykleja kontrolkę do krawędzi:Top,Bottom,Left,Right.- Dzieci są rozmieszczane w kolejności z XAML — pierwsze dostaje pełną długość krawędzi. Najpierw paski, potem panele boczne.
- Przy
LastChildFill="True"ostatnie dziecko wypełnia resztę okna — tam stawiasz główną treść. DockPaneldla całego okna,Griddla formularzy i proporcji — łączenie paneli to normalna praktyka.SelectedTextwstawia tekst w miejscu kursora, aCaretIndexprzesuwa kursor.
Dokumentacja: Microsoft Learn — DockPanel.