XAML – język opisu interfejsu

Poznasz składnię XAML – języka, w którym opisujesz jak wygląda Twoja aplikacja. Dowiesz się jak działają elementy, atrybuty i jak XAML łączy się z kodem C#.

XAML atrybuty x:Name XAML ↔ C#
1

Czym jest XAML?

XAML (czytaj: „zaml”, ang. eXtensible Application Markup Language) to język, w którym opisujesz jak wygląda Twoja aplikacja – jakie ma przyciski, pola tekstowe, gdzie są rozmieszczone i jakiego są koloru.

Analogia do strony internetowej

Jeśli kiedykolwiek widziałeś HTML, XAML będzie Ci znajomy. Tak jak HTML opisuje co jest na stronie internetowej, XAML opisuje co jest w oknie aplikacji WPF. C# to logika – co się dzieje gdy użytkownik coś kliknie.

Strona WWWAplikacja WPF
HTML – struktura i treśćXAML – wygląd okna
CSS – style i koloryXAML Styles – style i kolory
JavaScript – logikaC# – logika

XAML opiera się na XML – jeśli znasz HTML, składnia będzie Ci bliska. Elementy mają otwierający znacznik <Nazwa>, zamykający </Nazwa>, i mogą być samozamykające: <Nazwa />.

2

Składnia XAML

Elementy i atrybuty

Każda kontrolka w XAML to element – zapisany w nawiasach trójkątnych. Właściwości kontrolki to atrybuty – zapisane wewnątrz tagu w formacie Nazwa="Wartość".

Anatomia elementu XAML
<!--  element ↓          atrybut="wartość"  -->
<Button Content="Kliknij mnie"
        Width="120"
        Height="35"
        Background="SteelBlue"
        Foreground="White" />
<!--                                    ↑ samozamykający -->

Samozamykający znacznik /> na końcu stosujemy wtedy, gdy element nie ma dzieci (nie zawiera innych elementów w środku).

Element z zawartością (dziećmi)
<!-- Jeśli element ma zawartość – używamy pary znaczników -->
<StackPanel>
    <Button Content="Przycisk 1" />
    <Button Content="Przycisk 2" />
    <Button Content="Przycisk 3" />
</StackPanel>
<!-- ↑ StackPanel "zawiera" trzy przyciski -->

Zagnieżdżanie elementów

Elementy XAML mogą być zagnieżdżane – jeden wewnątrz drugiego. Tworzy to drzewo elementów. Każdy element ma swojego rodzica i może mieć dzieci.

Drzewo elementów
<Window>                    <!-- korzeń – okno -->
    <Grid>                  <!-- Grid jest dzieckiem Window -->
        <StackPanel>        <!-- StackPanel jest dzieckiem Grid -->
            <TextBlock Text="Witaj!" />   <!-- dziecko StackPanel -->
            <Button    Content="OK"    />   <!-- dziecko StackPanel -->
        </StackPanel>
    </Grid>
</Window>
Ważna zasada

Większość kontenerów layoutu (Grid, StackPanel, DockPanel) może mieć wiele dzieci. Ale samo okno <Window> i wiele kontrolek (np. <Button>) może mieć tylko jedno dziecko. Dlatego wewnątrz okna zawsze musi być najpierw kontener (np. Grid), a dopiero w nim reszta elementów.

Komentarze w XAML

Komentarze zapisujemy tak samo jak w HTML:

Komentarze
<Grid>

    <!-- To jest komentarz – nie pojawi się w aplikacji -->
    <Button Content="OK" />

    <!--
        Komentarz może być
        wieloliniowy
    -->

</Grid>
3

Dwa sposoby zapisu właściwości

Właściwości kontrolki możesz zapisać na dwa sposoby. Oba dają ten sam efekt – różnią się tylko składnią.

Sposób 1 – Atrybut (krótki zapis)

Najprostszy i najczęściej używany. Właściwość to atrybut bezpośrednio wewnątrz tagu – wartość zawsze w cudzysłowie.

Zapis atrybutowy – krótki i wygodny
<Button Content="Zapisz"
        Width="100"
        Height="35"
        Background="SteelBlue"
        Foreground="White" />

Sposób 2 – Element właściwości (rozbudowany zapis)

Gdy wartość właściwości jest złożona – np. gradient kolorów, lub gdy nie zmieści się w jednej linii jako tekst – używamy zapisu elementowego. Wygląda jak zagnieżdżony element z kropką w nazwie: <NazwaKontrolki.NazwaWłaściwości>.

Zapis elementowy – dla złożonych wartości
<Button Width="150" Height="50">

    <!-- Właściwość Content zapisana jako element -->
    <Button.Content>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="💾 Zapisz" />
        </StackPanel>
    </Button.Content>

    <!-- Właściwość Background zapisana jako gradient -->
    <Button.Background>
        <LinearGradientBrush>
            <GradientStop Color="SteelBlue" Offset="0" />
            <GradientStop Color="DarkBlue"  Offset="1" />
        </LinearGradientBrush>
    </Button.Background>

</Button>
Kiedy używać którego?
SytuacjaUżyj
Prosta wartość: tekst, liczba, kolor po nazwieAtrybutu: Background="Red"
Złożona wartość: gradient, szablon, powiązanie danychElementu właściwości
Zawartość kontrolki to inna kontrolkaElementu właściwości

Na początku kursu prawie zawsze wystarczy zapis atrybutowy. Elementowego będziesz używać częściej w zaawansowanych tematach (Style, Data Binding, animacje).

4

Nazywanie elementów – x:Name

Aby móc odwołać się do kontrolki z kodu C#, musisz nadać jej nazwę za pomocą atrybutu x:Name. Bez nazwy kontrolka jest anonimowa – widać ją w oknie, ale nie możesz jej dotknąć z C#.

Nadawanie nazwy elementom
<Grid>

    <!-- Przycisk bez nazwy – nie można go obsłużyć z C# -->
    <Button Content="Anonimowy" />

    <!-- Przycisk z nazwą – można go używać z C# -->
    <Button x:Name="btnZapisz"
            Content="Zapisz"
            Click="btnZapisz_Click" />

    <!-- Pole tekstowe z nazwą -->
    <TextBox x:Name="txtImie" />

    <!-- Etykieta wynikowa z nazwą -->
    <TextBlock x:Name="lblWynik" Text="Wynik: –" />

</Grid>
Używanie nazw w C#
private void btnZapisz_Click(object sender, RoutedEventArgs e)
{
    // Dzięki x:Name możemy odczytać tekst z pola
    string imie = txtImie.Text;

    // I wyświetlić go w etykiecie
    lblWynik.Text = $"Witaj, {imie}!";

    // Możemy też wyłączyć przycisk po kliknięciu
    btnZapisz.IsEnabled = false;
}
Zasada

Nadawaj nazwy tylko tym kontrolkom, do których będziesz odwoływać się z C#. Layoutów (Grid, StackPanel) zwykle nie nazywamy, chyba że są potrzebne w kodzie. Nie nazywaj wszystkiego z przyzwyczajenia – niepotrzebne nazwy zaśmiecają kod.

Name vs x:Name

W WPF można użyć zarówno x:Name jak i Name – dla kontrolek działają identycznie. Przyjęło się używać x:Name, bo jest bardziej jawne i działa wszędzie (np. przy własnych kontrolkach).

5

XAML ↔ C# – jak to działa?

XAML i C# to dwie strony tej samej monety. XAML opisuje wygląd, C# opisuje zachowanie. Razem tworzą jedno okno.

Jak to działa pod spodem?

Kiedy kompilujesz projekt, Visual Studio zamienia Twój plik XAML na kod C# – tworzy metodę InitializeComponent(), która buduje wszystkie kontrolki w pamięci. Twój plik MainWindow.xaml.cs i ten wygenerowany kod to razem jedna klasa (słowo kluczowe partial).

Odczytywanie właściwości z C#

MainWindow.xaml – kontrolki
<StackPanel>
    <TextBox   x:Name="txtImie"   Text="Jan"  />
    <TextBox   x:Name="txtWiek"   Text="18"  />
    <TextBlock x:Name="lblWynik"  Text="–"   />
    <Button    x:Name="btnSprawdz"
               Content="Sprawdź"
               Click="btnSprawdz_Click" />
</StackPanel>
MainWindow.xaml.cs – odczyt danych
private void btnSprawdz_Click(object sender, RoutedEventArgs e)
{
    // Odczytujemy Text z TextBox
    string imie = txtImie.Text;

    // Konwersja tekstu na liczbę
    int wiek;
    if (!int.TryParse(txtWiek.Text, out wiek))
    {
        lblWynik.Text = "Wiek musi być liczbą!";
        return;
    }

    // Zapisujemy wynik do TextBlock
    lblWynik.Text = $"Cześć {imie}, masz {wiek} lat.";
}

Zmiana właściwości z C#

Każdy atrybut z XAML ma odpowiadającą mu właściwość w C#. Możesz je zmieniać w dowolnym momencie działania programu.

Zmiana właściwości kontrolek z C#
// Zmiana tekstu
lblWynik.Text = "Nowy tekst";

// Włączenie / wyłączenie kontrolki
btnZapisz.IsEnabled = false;

// Ukrycie kontrolki
btnZapisz.Visibility = Visibility.Hidden;    // niewidoczna, ale zajmuje miejsce
btnZapisz.Visibility = Visibility.Collapsed; // niewidoczna, nie zajmuje miejsca
btnZapisz.Visibility = Visibility.Visible;   // widoczna (domyślne)

// Zmiana koloru tła
btnZapisz.Background = new SolidColorBrush(Colors.Green);

// Zmiana rozmiaru czcionki
lblWynik.FontSize = 18;

// Zmiana szerokości i wysokości
btnZapisz.Width  = 200;
btnZapisz.Height = 50;
Visibility – trzy stany
WartośćWidoczna?Zajmuje miejsce?Kiedy używać?
Visible✅ Tak✅ TakNormalny stan
Hidden❌ Nie✅ TakUkrywanie bez przesuwania innych
Collapsed❌ Nie❌ NieUkrywanie z usuniętym miejscem

Tworzenie elementów w C# (bez XAML)

Wszystko co możesz zrobić w XAML, możesz też zrobić w C#. Przydaje się gdy chcesz dynamicznie tworzyć kontrolki (np. w pętli).

Tworzenie kontrolek w C# – odpowiednik XAML
// To samo co <Button Content="Kliknij" Width="100" Background="Red"/>
Button btn = new Button();
btn.Content    = "Kliknij";
btn.Width      = 100;
btn.Background = new SolidColorBrush(Colors.Red);
btn.Click      += MojPrzycisk_Click;

// Dodanie do istniejącego StackPanel o nazwie panelGlowny
panelGlowny.Children.Add(btn);


// Tworzenie wielu przycisków w pętli
for (int i = 1; i <= 5; i++)
{
    Button nowyBtn = new Button();
    nowyBtn.Content = $"Przycisk {i}";
    nowyBtn.Margin  = new Thickness(5);
    panelGlowny.Children.Add(nowyBtn);
}
Pamiętaj

Kontrolki tworzone w C# musisz dodać do kontenera (Children.Add()), żeby pojawiły się na ekranie. Sam fakt new Button() nic nie wyświetla.

6

Konwencja nazewnictwa kontrolek

Dobrą praktyką jest nazywanie kontrolek z przedrostkiem oznaczającym ich typ. Dzięki temu od razu wiesz z jakiej kontrolki korzystasz w kodzie C# – bez zaglądania do XAML.

KontrolkaPrzedrostekPrzykłady nazw
ButtonbtnbtnZapisz, btnAnuluj, btnUsun
TextBoxtxttxtImie, txtEmail, txtHaslo
TextBlocklbl lub tblblWynik, lblBladStanu
LabellbllblTytul, lblOpis
CheckBoxchkchkZapisz, chkZalogowany
RadioButtonrbrbMezczyzna, rbKobieta
ComboBoxcmbcmbKategoria, cmbRok
ListBoxlstlstProdukty, lstUzytkownicy
ListViewlvlvZamowienia, lvWyniki
DataGriddgdgPracownicy, dgTowary
ImageimgimgAwatar, imgLogo
SlidersldsldGlosnosc, sldJasnosc
ProgressBarpbpbPostep, pbLadowanie
PasswordBoxpwdpwdHaslo
TabControltabtabGlowny
CanvascvscvsPlanszaGry
Nazwy po polsku czy po angielsku?

W projektach edukacyjnych możesz używać polskich nazw (bez polskich liter!) – btnZapisz, txtImie, lblWynik. W projektach zawodowych dominuje angielski – btnSave, txtName, lblResult. Najważniejsza zasada: bądź konsekwentny – wybierz jeden język i trzymaj się go w całym projekcie.

7

Częste błędy w XAML

❌ Błąd 1: Niezamknięty znacznik

❌ Źle – brak zamknięcia

<Button Content="OK">
<!-- Brak </Button> lub /> -->
<TextBlock Text="Witaj" />

Błąd kompilacji: XAML jest nieprawidłowy.

✅ Dobrze

<Button Content="OK" />
<TextBlock Text="Witaj" />

❌ Błąd 2: Dwa dzieci w Window

❌ Źle – Window ma dwa dzieci

<Window>
    <Button Content="Jeden" />
    <Button Content="Dwa" />
    <!-- Błąd! Window może mieć
         tylko jedno dziecko -->
</Window>

✅ Dobrze – kontener jako jedyne dziecko

<Window>
    <StackPanel>
        <Button Content="Jeden" />
        <Button Content="Dwa" />
    </StackPanel>
</Window>

❌ Błąd 3: Wielkość liter w nazwach

❌ Źle – błędna wielkość liter

<button content="OK" />
<!-- XAML rozróżnia
     wielkie i małe litery!
     "button" ≠ "Button" -->

✅ Dobrze – PascalCase

<Button Content="OK" />
<!-- Nazwy elementów i
     atrybutów zawsze
     z wielkiej litery -->

❌ Błąd 4: Odwołanie do kontrolki bez nazwy

❌ Źle – brak x:Name

// XAML:
<TextBox Text="coś" />

// C# – błąd kompilacji:
txtImie.Text = "Jan"; // skąd?
// Kontrolka nie ma nazwy!

✅ Dobrze – z x:Name

// XAML:
<TextBox x:Name="txtImie" />

// C# – działa:
txtImie.Text = "Jan"; // OK!

❌ Błąd 5: Brak cudzysłowu przy atrybucie

❌ Źle

<Button Width=100 />
<!-- Brak cudzysłowu
     = błąd XAML -->

✅ Dobrze

<Button Width="100" />
<!-- Wartości ZAWSZE
     w cudzysłowie -->
8

Zadania do wykonania

Zadanie 1 łatwe

W pliku XAML napisz okno z StackPanel zawierającym:

  • Trzy TextBlock z różnymi tekstami
  • Trzy Button z różnymi napisami i kolorami tła

Każdy element zapisz najpierw jako jeden atrybut (krótki zapis), a potem spróbuj przepisać go na zapis elementowy.

Zadanie 2 łatwe

Stwórz okno z TextBox (pole na imię) i Button (przycisk „Powitaj”). Po kliknięciu przycisku odczytaj imię z TextBox i wyświetl powitanie w TextBlock. Pamiętaj o nadaniu nazw przez x:Name!

Zadanie 3 łatwe

Dodaj do okna z zadania 2 drugi przycisk „Wyczyść”. Po jego kliknięciu niech czyści pole TextBox oraz tekst w TextBlock, a siebie samego wyłączy (IsEnabled = false). Po wpisaniu czegokolwiek w TextBox przycisk „Wyczyść” ma się włączyć z powrotem (TextChanged).

Zadanie 4 średnie

W obsłudze zdarzenia Window_Loaded dynamicznie utwórz w C# (bez XAML) 5 przycisków i dodaj je do StackPanel. Każdy przycisk ma mieć napis „Przycisk 1″, „Przycisk 2″… itd. Po kliknięciu dowolnego przycisku TextBlock ma wyświetlić który przycisk został kliknięty.

// Podpowiedź: aby wiedzieć który przycisk kliknięto,
// użyj parametru sender i rzutowania:
Button klikniety = (Button)sender;
lblWynik.Text = $"Kliknięto: {klikniety.Content}";