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

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.

XAML C# DockPanel DockPanel.Dock LastChildFill 90 min
CEL LEKCJI

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 LastChildFill i 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, Grid albo oba naraz.
TEORIA

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.

MainWindow.xaml
<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>
DockPanel–□✕
Pasek u góry
Panel boczny
Treść — wypełnia resztę
Pasek stanu

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.

TEORIA

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:

1. Top
2. Left
3. treść

najpierw Top: pasek nad panelem bocznym

1. Left
2. Top
3. treść

najpierw Left: panel boczny na całą wysokość

Zasada praktyczna: najpierw paski na całą szerokość (Top, Bottom), potem panele boczne, na końcu treść.

TEORIA

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.

MainWindow.xaml
<!-- 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.

TEORIA

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.

PotrzebaWybór
pasek u góry, pasek stanu, panel boczny, treśćDockPanel
etykiety i pola w równych kolumnachGrid
dwie kolumny w proporcji 1 : 3Grid
przyciski dosunięte do prawej w jednym rzędzieStackPanel z HorizontalAlignment="Right" albo DockPanel z LastChildFill="False"
PRZYKŁAD

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.

Notatnik szkolny–□✕
Nowy
Wstaw datę
A+
A−
Szablony
Usprawiedliwienie
Notatka z lekcji
Lista zakupów
Temat: DockPanel
Najważniejsze pojęcia:
– DockPanel.Dock
– LastChildFill
Zadanie domowe: zad 3 i 4, termin 08.10.2026
Znaków: 121 | Słów: 16 | Rozmiar: 14

po wstawieniu szablonu „Notatka z lekcji” i uzupełnieniu go

MainWindow.xaml — pełny plik
<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 …&#x0a;Powód: …&#x0a;Podpis rodzica: …"/>
                <Button Content="Notatka z lekcji" Margin="0,0,0,4" Click="Szablon_Click"
                        Tag="Temat: …&#x0a;Najważniejsze pojęcia:&#x0a;- …&#x0a;Zadanie domowe: …"/>
                <Button Content="Lista zakupów" Click="Szablon_Click"
                        Tag="Do kupienia:&#x0a;- zeszyt&#x0a;- długopis&#x0a;- …"/>
            </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>
MainWindow.xaml.cs — pełny plik
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 Tekst nie ma DockPanel.Dock — jako ostatnie dziecko wypełnia resztę okna i rośnie razem z nim.
  • Panel szablonów to Border z Width="160" i linią tylko po prawej stronie (BorderThickness="0,0,1,0"), która oddziela go od treści.
  • Treść szablonów jest w Tag przycisków. &#x0a; 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 odczytuje Tag klikniętego przycisku.
  • Wstaw używa SelectedText: przypisanie wstawia tekst w miejscu kursora, a jeśli coś było zaznaczone — zastępuje zaznaczenie. Potem kursor jest przesuwany za wstawkę przez CaretIndex.
  • Liczba słów to liczba kawałków po podziale tekstu na spacjach, tabulatorach i znakach nowej linii; RemoveEmptyEntries pomija puste kawałki między dwiema spacjami.
  • Nowy pyta o potwierdzenie tylko wtedy, gdy notatka nie jest pusta.

Sprawdź trzy rzeczy

  1. Przenieś w XAML panel szablonów (Border z Left) na samą górę DockPanel. Panel zajmie całą wysokość okna, a paski skrócą się do prawej części.
  2. Przenieś TextBox przed pasek stanu. Teraz ostatnim dzieckiem jest pasek stanu — wypełni on środek okna, a notatka przyklei się do lewej.
  3. Zaznacz myszą słowo w notatce i kliknij Wstaw datę. Data zastąpi zaznaczone słowo.
ELEMENTY WBUDOWANE

Zestawienie elementów

ElementTyp / wartościCo robi
DockPanel.DockTop, Bottom, Left, RightWłaściwość dołączona — do której krawędzi przykleić kontrolkę. Domyślnie Left.
LastChildFillboolTrue (domyślnie) — ostatnie dziecko wypełnia resztę.
TextBox.SelectedTextstringZaznaczony tekst; przypisanie wstawia tekst w miejscu kursora.
CaretIndexintPozycja kursora w polu (liczba znaków przed kursorem).
SelectionStart, SelectionLengthintPoczątek i długość zaznaczenia.
Split(tablicaZnakow, StringSplitOptions.RemoveEmptyEntries)string[]Dzieli tekst na kawałki według kilku separatorów, pomija puste.
&#x0a;XAMLZnak nowej linii w wartości atrybutu.
CZĘSTE BŁĘDY

Zanim utkniesz

ZapisProblem
treść w środku listy dzieci, a pasek stanu na końcuPasek 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 dzieckuIgnorowane przy LastChildFill="True" — kontrolka i tak wypełnia resztę.
panel boczny przed paskamiPanel 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 tekstemPanel jest tak szeroki jak najdłuższy tekst i może zabrać większość okna.
nowa linia wpisana Enter w atrybucie TagXAML zamienia ją na spację. Użyj &#x0a;.
ZADANIA

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.

ZAD 1Odtwarzacz muzyki★☆☆

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.
ZAD 2Laboratorium dokowania★☆☆

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.
ZAD 3Książka kucharska★★☆

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: przycisk Left, przycisk Right, napis jako ostatnie dziecko z TextAlignment="Center".
  • Wszystko, co zależy od numeru przepisu, ustawiaj w jednej metodzie PokazPrzepis(int numer).
ZAD 4Konwerter tekstu★★☆

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żyj Array.Reverse i zbuduj napis przez new string(tablica).
  • Polskie znaki: dwa napisy "ąćęłńóśźżĄĆĘŁŃÓŚŹŻ" i "acelnoszzACELNOSZZ" oraz pętla z IndexOf.
ZAD 5Panel administratora pracowni★★☆

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.Row w jednej komórce nakładają się — przełączasz je przez Visibility (lekcja 05).
  • Stanowiska utwórz w pętli w UniformGrid 4 × 4, stan zapisuj w Tag.
ZAD 6Edytor plakatu ogłoszenia★★★

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: Border z 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 MessageBox z pełnym tekstem plakatu.
pokaż wskazówkę
  • Kolejność w głównym DockPanel: góra, dół, lewa, podgląd. Dolny pasek to kolejny DockPanel z przyciskiem Right i napisem jako ostatnim dzieckiem.
  • Wszystkie pola mogą mieć jedną metodę TextChanged, która przepisuje cały podgląd.
  • W Tag przycisku motywu zapisz jego numer, a pędzle tła i tekstu dobierz w switch. Bieżący motyw pamiętaj w polu klasy.
PODSUMOWANIE

Co trzeba zapamiętać

  • DockPanel.Dock przykleja 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ść.
  • DockPanel dla całego okna, Grid dla formularzy i proporcji — łączenie paneli to normalna praktyka.
  • SelectedText wstawia tekst w miejscu kursora, a CaretIndex przesuwa kursor.

Dokumentacja: Microsoft Learn — DockPanel.

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