StackPanel – układ liniow

Poznasz StackPanel – layout, który układa elementy jeden za drugim, pionowo lub poziomo. Prosty, szybki i idealny do list przycisków, pasków narzędzi i formularzy.

StackPanel Orientation Margin / Padding Alignment
1

Czym jest StackPanel?

StackPanel to layout, który układa swoje elementy jeden za drugim – jak stos kart albo kolejka. Możesz ustawić kierunek: pionowy (jeden pod drugim) lub poziomy (jeden obok drugiego).

Analogia

Wyobraź sobie, że wkładasz książki na półkę. Możesz ustawiać je pionowo – jedną na drugiej (jak wieża) lub poziomo – jedną obok drugiej (jak normalnie w bibliotece). StackPanel działa dokładnie tak. Każdy nowy element trafia na koniec kolejki.

StackPanel jest prostszy niż Grid – nie musisz definiować wierszy ani kolumn. Elementy po prostu stoją po sobie. Płacisz za to pewną cenę: mniej kontroli nad rozmieszczeniem.

2

Orientation – kierunek układania

Vertical – jeden pod drugim (domyślny)

Domyślnie StackPanel układa elementy od góry do dołu. Nie musisz nawet pisać Orientation="Vertical" – tak jest domyślnie.

StackPanel pionowy
<!-- Orientation="Vertical" jest domyślne – można pominąć -->
<StackPanel Orientation="Vertical">
    <Button Content="Pierwszy"  Margin="5" />
    <Button Content="Drugi"     Margin="5" />
    <Button Content="Trzeci"    Margin="5" />
</StackPanel>
<!-- Wynik: trzy przyciski jeden pod drugim -->
Ważna cecha pionowego StackPanel

W trybie Vertical każdy element rozciąga się na całą szerokość StackPanel (HorizontalAlignment = Stretch domyślnie). Dlatego przyciski są tak szerokie jak cały panel. Możesz to zmienić ustawiając HorizontalAlignment="Left" lub podając konkretną szerokość Width="100".

Horizontal – jeden obok drugiego

Po ustawieniu Orientation="Horizontal" elementy układają się od lewej do prawej.

StackPanel poziomy
<StackPanel Orientation="Horizontal">
    <Button Content="Cofnij"   Margin="5" />
    <Button Content="Dalej"    Margin="5" />
    <Button Content="Anuluj"   Margin="5" />
    <Button Content="Zapisz"   Margin="5" />
</StackPanel>
<!-- Wynik: cztery przyciski obok siebie -->
Ważna cecha poziomego StackPanel

W trybie Horizontal każdy element rozciąga się na całą wysokość StackPanel (VerticalAlignment = Stretch domyślnie). Jeśli nie chcesz tego efektu, ustaw konkretną wysokość lub VerticalAlignment="Center" na elementach.

3

Odstępy między elementami

Domyślnie elementy w StackPanel stoją ciasno obok siebie – bez żadnych odstępów. Są dwa sposoby, żeby to poprawić.

Margin na elementach-dzieciach

Najczęstszy sposób – każdemu elementowi dajesz Margin. Pamiętaj, że Margin dodaje przestrzeń z każdej strony, więc między dwoma elementami z Margin="5" będzie 10px odstępu (5px górnego + 5px dolnego).

Margin na dzieciach
<!-- Każdy element ma 5px marginesu ze wszystkich stron -->
<StackPanel>
    <Button Content="Nowy"   Margin="5" />
    <Button Content="Otwórz" Margin="5" />
    <Button Content="Zapisz" Margin="5" />
</StackPanel>

<!-- Margines tylko pionowy – lewa/prawa = 0, góra/dół = 4 -->
<StackPanel>
    <TextBlock Text="Imię:"     Margin="0,0,0,4" />
    <TextBox                        Margin="0,0,0,12" />
    <TextBlock Text="Nazwisko:" Margin="0,0,0,4" />
    <TextBox                        Margin="0,0,0,12" />
</StackPanel>

Padding na samym StackPanel

Padding dodaje wewnętrzny odstęp między krawędzią StackPanel a jego zawartością – działa jak margines od wnętrza kontenera.

Padding na StackPanel
<!-- 10px odstępu od krawędzi panelu do zawartości -->
<StackPanel Padding="10">
    <Button Content="Jeden"   Margin="0,0,0,5" />
    <Button Content="Dwa"     Margin="0,0,0,5" />
    <Button Content="Trzy"    />
</StackPanel>
Padding + Margin razem – jak to działa

Padding = przestrzeń od krawędzi panelu do pierwszego elementu.
Margin na dziecku = przestrzeń między tym elementem a sąsiednimi. Najczęściej używa się albo jednego albo drugiego – stosowanie obu naraz może dawać nieoczekiwane efekty.

4

Wyrównanie elementów

Domyślnie dzieci StackPanel rozciągają się na całą dostępną szerokość (w trybie pionowym) lub wysokość (w trybie poziomym). Możesz to zmienić na dwóch poziomach: na całym panelu lub na poszczególnych elementach.

Wyrównanie całego StackPanel w rodzicu
<!-- StackPanel wyrównany do prawej strony okna -->
<StackPanel Orientation="Horizontal"
            HorizontalAlignment="Right"
            VerticalAlignment="Bottom"
            Margin="10">
    <Button Content="Anuluj" Margin="5,0" Width="80" />
    <Button Content="Zapisz"  Margin="5,0" Width="80" />
</StackPanel>
<!-- Dwa przyciski w prawym dolnym rogu -->
Wyrównanie poszczególnych dzieci
<StackPanel>
    <!-- Każde dziecko ma inne wyrównanie -->
    <Button Content="Do lewej"
            HorizontalAlignment="Left"
            Width="100"
            Margin="5" />

    <Button Content="Na środku"
            HorizontalAlignment="Center"
            Width="100"
            Margin="5" />

    <Button Content="Do prawej"
            HorizontalAlignment="Right"
            Width="100"
            Margin="5" />

    <Button Content="Pełna szerokość"
            HorizontalAlignment="Stretch"
            Margin="5" />
</StackPanel>
5

Zagnieżdżanie StackPaneli

StackPanel możesz zagnieżdżać – pionowy wewnątrz poziomego i odwrotnie. To prosty sposób na budowanie złożonych układów bez użycia Grid.

Zagnieżdżony StackPanel – nagłówek + treść + stopka
<!-- Zewnętrzny pionowy -->
<StackPanel Orientation="Vertical" Margin="10">

    <!-- Nagłówek -->
    <TextBlock Text="Dodaj produkt"
               FontSize="18"
               FontWeight="Bold"
               Margin="0,0,0,10" />

    <!-- Wiersz: Etykieta + Pole (poziomy StackPanel) -->
    <StackPanel Orientation="Horizontal" Margin="0,0,0,8">
        <TextBlock Text="Nazwa:"
                   Width="80"
                   VerticalAlignment="Center" />
        <TextBox   x:Name="txtNazwa"
                   Width="200" />
    </StackPanel>

    <!-- Wiersz: Etykieta + Pole -->
    <StackPanel Orientation="Horizontal" Margin="0,0,0,8">
        <TextBlock Text="Cena:"
                   Width="80"
                   VerticalAlignment="Center" />
        <TextBox   x:Name="txtCena"
                   Width="200" />
    </StackPanel>

    <!-- Stopka: przyciski w poziomie, do prawej -->
    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Right"
                Margin="0,10,0,0">
        <Button Content="Anuluj" Width="80" Margin="0,0,8,0" />
        <Button Content="Dodaj"   Width="80" />
    </StackPanel>

</StackPanel>
Kiedy zagnieżdżać, a kiedy użyć Grid?

Zagnieżdżone StackPanele dobrze sprawdzają się przy prostych, liniowych layoutach. Gdy potrzebujesz, żeby pole tekstowe zajmowało resztę dostępnej przestrzeni (*), a etykieta była tylko tak szeroka jak jej tekst – sięgnij po Grid z Width="Auto" i Width="*". Zagnieżdżone StackPanele mają stałe szerokości, co bywa ograniczające.

6

StackPanel w C#

StackPanel możesz tworzyć i modyfikować z kodu C#. Przydaje się gdy chcesz dynamicznie dodawać elementy – np. wczytując dane z listy.

Dynamiczne dodawanie elementów do StackPanel
// W XAML: <StackPanel x:Name="panelListy" />

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    string[] produkty = { "Jabłko", "Banan", "Gruszka", "Śliwka" };

    foreach (string produkt in produkty)
    {
        // Tworzymy wiersz: poziomy StackPanel
        StackPanel wiersz = new StackPanel();
        wiersz.Orientation = Orientation.Horizontal;
        wiersz.Margin = new Thickness(0, 0, 0, 5);

        // Etykieta z nazwą produktu
        TextBlock etykieta = new TextBlock();
        etykieta.Text = produkt;
        etykieta.Width = 120;
        etykieta.VerticalAlignment = VerticalAlignment.Center;

        // Przycisk usuń
        Button btnUsun = new Button();
        btnUsun.Content = "Usuń";
        btnUsun.Tag = produkt;   // zapamiętujemy który produkt
        btnUsun.Click += BtnUsun_Click;

        // Składamy wiersz
        wiersz.Children.Add(etykieta);
        wiersz.Children.Add(btnUsun);

        // Dodajemy wiersz do panelu głównego
        panelListy.Children.Add(wiersz);
    }
}

private void BtnUsun_Click(object sender, RoutedEventArgs e)
{
    Button btn = (Button)sender;
    string nazwa = (string)btn.Tag;
    MessageBox.Show($"Usuwam: {nazwa}");
}
Właściwość Tag

Tag to specjalna właściwość dostępna na każdej kontrolce WPF. Możesz tam przechować dowolny obiekt – tekst, liczbę, referencję. Przydaje się gdy tworzysz kontrolki dynamicznie i chcesz każdej z nich przypisać dane, do których wrócisz później (np. w obsłudze zdarzenia Click).

7

StackPanel vs Grid – kiedy co używać?

Sytuacja StackPanel Grid
Kilka przycisków obok siebie ✅ Idealny ➖ Zbędna złożoność
Lista elementów jeden pod drugim ✅ Idealny ➖ Da radę, ale więcej kodu
Formularz: etykieta + pole tekstowe ⚠️ Da radę (stałe szerokości) ✅ Lepszy (Auto + *)
Pole ma zajmować „resztę” przestrzeni ❌ Nie potrafi Width="*"
Pasek przycisków (toolbar) ✅ Idealny (Horizontal) ➖ Można, ale po co
Dynamiczne dodawanie elementów ✅ Bardzo wygodny ⚠️ Trudniejszy w C#
Precyzyjne rozmieszczenie w oknie ❌ Brak kontroli ✅ Pełna kontrola
Praktyczna zasada

Używaj StackPanel gdy chcesz szybko ułożyć kilka elementów w linię – pasek przycisków, lista pozycji, prosta nawigacja. Używaj Grid gdy potrzebujesz precyzyjnego rozmieszczenia i kontroli nad rozmiarem – formularze, okna dialogowe, cały layout okna. W prawdziwych aplikacjach oba layouty współpracują: Grid jako szkielet okna, StackPanel do grupowania przycisków i małych elementów.

8

Praktyczne przykłady

Pasek przycisków akcji

Toolbar z przyciskami – typowy wzorzec
<!-- Pasek z przyciskami: po lewej "Nowy", po prawej "Anuluj/Zapisz" -->
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"    />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <!-- Przyciski po lewej -->
    <StackPanel Grid.Column="0"
                Orientation="Horizontal">
        <Button Content="➕ Nowy"   Margin="0,0,5,0" Padding="10,5" />
        <Button Content="🗑 Usuń"   Margin="0,0,5,0" Padding="10,5" />
    </StackPanel>

    <!-- Przyciski po prawej -->
    <StackPanel Grid.Column="1"
                Orientation="Horizontal">
        <Button Content="Anuluj" Margin="0,0,5,0" Width="70" />
        <Button Content="Zapisz"  Width="70" />
    </StackPanel>
</Grid>

Menu boczne (nawigacja)

Panel nawigacyjny po lewej stronie
<!-- Panel boczny z menu nawigacyjnym -->
<StackPanel Background="#2d2d3f"
            Width="180"
            Padding="0,10">

    <TextBlock Text="MENU"
               Foreground="#888"
               FontSize="11"
               Margin="15,0,0,8" />

    <Button Content="🏠  Strona główna"
            HorizontalAlignment="Stretch"
            HorizontalContentAlignment="Left"
            Padding="15,10"
            Margin="0,1"
            BorderThickness="0"
            Background="Transparent"
            Foreground="White" />

    <Button Content="📋  Lista produktów"
            HorizontalAlignment="Stretch"
            HorizontalContentAlignment="Left"
            Padding="15,10"
            Margin="0,1"
            BorderThickness="0"
            Background="Transparent"
            Foreground="White" />

    <Button Content="⚙️  Ustawienia"
            HorizontalAlignment="Stretch"
            HorizontalContentAlignment="Left"
            Padding="15,10"
            Margin="0,1"
            BorderThickness="0"
            Background="Transparent"
            Foreground="White" />
</StackPanel>

Formularz pionowy – prosty

Formularz logowania
<StackPanel Width="280"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Margin="20">

    <TextBlock Text="Logowanie"
               FontSize="22"
               FontWeight="Bold"
               HorizontalAlignment="Center"
               Margin="0,0,0,20" />

    <TextBlock Text="Login"     Margin="0,0,0,4" />
    <TextBox   x:Name="txtLogin"    Margin="0,0,0,12" Padding="5" />

    <TextBlock Text="Hasło"     Margin="0,0,0,4" />
    <PasswordBox x:Name="pwdHaslo"  Margin="0,0,0,20" Padding="5" />

    <Button x:Name="btnZaloguj"
            Content="Zaloguj się"
            Padding="0,10"
            Click="btnZaloguj_Click" />

</StackPanel>
9

Częste błędy w StackPanel

❌ Błąd 1: StackPanel nie scrolluje sam z siebie

❌ Elementy wychodzą poza ekran

<StackPanel>
  <!-- 50 elementów...
       te na dole niewidoczne,
       brak scrolla -->
</StackPanel>

✅ Owij w ScrollViewer

<ScrollViewer>
  <StackPanel>
    <!-- 50 elementów –
         teraz można scrollować -->
  </StackPanel>
</ScrollViewer>

❌ Błąd 2: Zapomniany Orientation

❌ Chciałem poziomo, wychodzi pionowo

<StackPanel>
  <!-- Domyślnie Vertical!
       Przyciski jeden pod drugim -->
  <Button Content="Jeden" />
  <Button Content="Dwa" />
</StackPanel>

✅ Jawnie ustawiony Orientation

<StackPanel Orientation="Horizontal">
  <Button Content="Jeden" />
  <Button Content="Dwa" />
</StackPanel>

❌ Błąd 3: Ustawianie Width=”*” w StackPanel

❌ * nie działa w StackPanel

<StackPanel Orientation="Horizontal">
  <TextBox Width="*" />
  <!-- Błąd! StackPanel nie
       obsługuje * jak Grid -->
</StackPanel>

✅ Do tego potrzebny jest Grid

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <TextBox Grid.Column="0" />
  <Button  Grid.Column="1"
           Content="Szukaj" />
</Grid>
10

Zadania do wykonania

Zadanie 1 łatwe

Stwórz okno z pionowym StackPanel zawierającym 5 przycisków: Poniedziałek, Wtorek, Środa, Czwartek, Piątek. Każdy przycisk po kliknięciu wyświetla w TextBlock (poza StackPanel) komunikat: „Wybrałeś: Środa”. Przyciski mają mieć szerokość 150px i być wyśrodkowane.

Zadanie 2 łatwe

Stwórz formularz logowania używając tylko StackPanel (bez Grid): tytuł, etykieta + pole login, etykieta + pole hasło, przycisk Zaloguj. Cały panel ma być wyśrodkowany na oknie i mieć szerokość 260px. Po kliknięciu „Zaloguj” sprawdź czy login to admin i hasło to 1234 – wyświetl odpowiedni komunikat.

Zadanie 3 średnie

W zdarzeniu Window_Loaded dynamicznie wygeneruj w C# listę 6 produktów (wymyśl je sam). Każdy produkt to poziomy StackPanel z: nazwą produktu (TextBlock) i przyciskiem „Dodaj do koszyka”. Po kliknięciu przycisku nazwa produktu trafia do ListBox umieszczonego obok panelu listy.

Zadanie 4 średnie

Zbuduj layout okna używając Grid + StackPanel:

  • Grid z 3 wierszami: nagłówek (Auto), treść (*), stopka (Auto)
  • W nagłówku: poziomy StackPanel z logo (TextBlock) po lewej i przyciskami nawigacji po prawej
  • W treści: dowolna zawartość (np. duże pole TextBox)
  • W stopce: poziomy StackPanel wyrównany do prawej z przyciskami „Anuluj” i „Zapisz”