У веб-розробці є CSS. Там ви пишете position: absolute; top: 100px; left: 200px і елемент опиниться рівно там, де ви хочете. Можна також написати position: fixed, z-index: 999, margin: auto і отримати бажаний результат.
WPF пропонує інший підхід — і він значно кращий для складних інтерфейсів.
У WPF немає "абсолютного позиціонування за замовчуванням". Якщо ви просто кинете кілька кнопок у Grid — вони всі виявляться одна поверх одної по центру. Щоб розташувати їх правильно — потрібна панель. Панель — це спеціальний контейнер, що знає алгоритм розміщення своїх дочірніх елементів.
Чому ця архітектура краща? Тому що:
StackPanel сам вириховує, де ставити наступну кнопку.DesiredSize. Arrange Pass — другий прохід: батько каже "ось тобі ця область (finalRect), розташуйся", дочірній малює себе. StackPanel — панель, що вкладає елементи вертикально або горизонтально один за одним. WrapPanel — як StackPanel, але з Orientation="Horizontal" переносить на новий рядок при нестачі місця. DockPanel — панель з "прикріпленням" елементів до сторін: Top, Bottom, Left, Right, і один (LastChildFill) займає решту.Перш ніж говорити про конкретні панелі — треба зрозуміти механізм, що лежить під усіма ними. Це двопрохідний алгоритм layout, який виконується щоразу, коли вікно змінює розмір або змінюється вміст.
На першому проході кожен елемент з'ясовує, скільки місця йому потрібно.
Алгоритм рекурсивний: батьківський елемент викликає Measure(availableSize) для кожного дочірнього. "Available size" — це скільки місця батько може потенційно надати. Дочірній вимірює себе (враховуючи свій вміст, шрифт, зображення) і зберігає результат у властивості DesiredSize.
// Спрощений вигляд того, що відбувається всередині WPF
protected override Size MeasureOverride(Size constraint)
{
// Запитуємо у дочірніх: "скільки місця вам треба?"
foreach (UIElement child in InternalChildren)
{
child.Measure(constraint); // constraint = скільки є у нас
// child.DesiredSize — тепер містить відповідь
}
// Повертаємо наш власний DesiredSize
return new Size(totalWidth, totalHeight);
}
Важливо: availableSize може містити double.PositiveInfinity по одній або обох осях. Це означає "місця необмежено — скільки треба". StackPanel у WPF передає нескінченний constraint по своїй осі розкладки: він говорить дочірнім "займайте стільки місця по вертикалі, скільки хочете".
На другому проході батьківський елемент розміщує дочірніх у конкретних прямокутниках.
Батько викликає Arrange(finalRect) для кожного дочірнього, передаючи Rect — точну позицію і розмір. Дочірній зобов'язаний розмістити себе у цій області. Він не може вийти за межі (WPF обріже зображення поза finalRect), але може розміститися менше ніж виділена область (якщо має HorizontalAlignment / VerticalAlignment).
// Спрощений Arrange у StackPanel
protected override Size ArrangeOverride(Size finalSize)
{
double y = 0; // Поточна вертикальна позиція
foreach (UIElement child in InternalChildren)
{
double childHeight = child.DesiredSize.Height;
// Ставимо дочірній елемент у прямокутник
child.Arrange(new Rect(0, y, finalSize.Width, childHeight));
y += childHeight; // Наступний елемент іде нижче
}
return finalSize;
}
Розуміння Measure/Arrange пояснює поведінку панелей без магії:
StackPanel не скролиться: По осі вкладання він передає дочірнім Infinity як constraint. Дочірні займають стільки, скільки хочуть. Батько StackPanel сам стає нескінченно великим. Якщо вікно менше — елементи просто обрізаються. Щоб мати скролл — треба обгорнути у ScrollViewer.Width="*" у Grid працює: GridColumn у фіналі Arrange розподіляє решту простору між зірочковими стовпцями.HorizontalAlignment="Center" не займає всю ширину: У Arrange він отримав широкий finalRect, але обрав лише DesiredSize.Width і центрував себе всередині.StackPanel — найпростіша і найчастіше вживана панель. Вона робить одну річ: вкладає дочірні елементи один за одним у вертикальному або горизонтальному напрямку.
За замовчуванням Orientation="Vertical". Кожен елемент іде під попереднім:
<StackPanel>
<TextBlock Text="Перший рядок"/>
<TextBlock Text="Другий рядок"/>
<TextBlock Text="Третій рядок"/>
<Button Content="Кнопка"/>
</StackPanel>
Що важливо: StackPanel розтягує дочірніх по поперечній осі (горизонталі у вертикальному StackPanel) до свого повного розміру. Тому кожен TextBlock і кожна Button займає повну ширину StackPanel. Але по основній осі (вертикалі) — елемент займає рівно стільки, скільки йому треба.
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<StackPanel Margin="16" Background="#f8fafc">
<TextBlock Text="Меню навігації"
FontSize="16" FontWeight="Bold"
Foreground="#1e293b" Margin="0,0,0,8"/>
<Button Content="🏠 Головна" Margin="0,2" Padding="12,8" HorizontalContentAlignment="Left"/>
<Button Content="👤 Профіль" Margin="0,2" Padding="12,8" HorizontalContentAlignment="Left"/>
<Button Content="⚙️ Налаштування" Margin="0,2" Padding="12,8" HorizontalContentAlignment="Left"/>
<Button Content="📊 Статистика" Margin="0,2" Padding="12,8" HorizontalContentAlignment="Left"/>
<Button Content="❓ Допомога" Margin="0,2" Padding="12,8" HorizontalContentAlignment="Left"/>
<Separator Margin="0,8"/>
<Button Content="🚪 Вийти" Margin="0,2" Padding="12,8"
Background="#fef2f2" Foreground="#dc2626"
HorizontalContentAlignment="Left"/>
</StackPanel>
Змінюємо Orientation="Horizontal" — і елементи вишиковуються в рядок:
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Зберегти"/>
<Button Content="Скасувати"/>
<Button Content="Попередній перегляд"/>
</StackPanel>
У горизонтальному StackPanel:
DesiredSize.WidthЯкщо ви хочете, щоб елементи не розтягувалися по висоті — задайте VerticalAlignment:
<StackPanel Orientation="Horizontal" Spacing="8" Height="60"
VerticalAlignment="Center">
<Button Content="Маленька" VerticalAlignment="Center" Padding="8,4"/>
<Button Content="Велика" Padding="8,12"/> <!-- Займе всю висоту -->
<Button Content="Середня" VerticalAlignment="Center" Padding="8,8"/>
</StackPanel>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<StackPanel Background="#1e293b">
<!-- Toolbar верхнього рівня -->
<StackPanel Orientation="Horizontal" Margin="8,4" Spacing="2">
<Button Content="📁 Файл" Padding="10,6" Background="Transparent" Foreground="White"/>
<Button Content="✏️ Правка" Padding="10,6" Background="Transparent" Foreground="White"/>
<Button Content="👁️ Вигляд" Padding="10,6" Background="Transparent" Foreground="White"/>
<Button Content="🔧 Сервіс" Padding="10,6" Background="Transparent" Foreground="White"/>
<Button Content="❓ Довідка" Padding="10,6" Background="Transparent" Foreground="White"/>
</StackPanel>
<Separator Background="#334155"/>
<!-- Toolbar з іконками дій -->
<StackPanel Orientation="Horizontal" Margin="8,4" Spacing="4">
<Button Content="📄" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Новий файл"/>
<Button Content="📂" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Відкрити"/>
<Button Content="💾" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Зберегти"/>
<Separator Width="1" Background="#475569" Margin="4,2"/>
<Button Content="↩️" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Скасувати"/>
<Button Content="↪️" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Повторити"/>
<Separator Width="1" Background="#475569" Margin="4,2"/>
<Button Content="🔍" Padding="8,6" Background="Transparent" Foreground="White" ToolTip="Пошук"/>
</StackPanel>
</StackPanel>
Spacing — відступи між елементамиУ WPF .NET 6+ у StackPanel доданий атрибут Spacing (спочатку лише в Avalonia, потім портований). Він задає відстань між елементами автоматично — без потреби руками задавати Margin кожному:
<!-- Без Spacing: треба задавати Margin кожному -->
<StackPanel>
<Button Content="Перша" Margin="0,0,0,8"/>
<Button Content="Друга" Margin="0,0,0,8"/>
<Button Content="Третя"/>
</StackPanel>
<!-- Зі Spacing: один атрибут на всіх -->
<StackPanel Spacing="8">
<Button Content="Перша"/>
<Button Content="Друга"/>
<Button Content="Третя"/>
</StackPanel>
Обидва дають однаковий результат — але Spacing значно зручніший і чистіший.
StackPanel легко вкладати: вертикальний StackPanel містить горизонтальні рядки, або навпаки:
<StackPanel Spacing="12" Margin="16">
<!-- Рядок 1: Поле вводу -->
<StackPanel>
<TextBlock Text="Ім'я користувача" FontWeight="SemiBold" Margin="0,0,0,4"/>
<TextBox Padding="8,6" PlaceholderText="Введіть ім'я..."/>
</StackPanel>
<!-- Рядок 2: Поле вводу -->
<StackPanel>
<TextBlock Text="Email" FontWeight="SemiBold" Margin="0,0,0,4"/>
<TextBox Padding="8,6" PlaceholderText="email@example.com"/>
</StackPanel>
<!-- Рядок 3: Горизонтальна пара кнопок -->
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right">
<Button Content="Скасувати" Padding="12,8"/>
<Button Content="Зберегти" Padding="12,8" Background="#2563eb" Foreground="White"/>
</StackPanel>
</StackPanel>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="White" Padding="24" CornerRadius="8" Margin="20"
BorderBrush="#e2e8f0" BorderThickness="1">
<StackPanel Spacing="16" Width="320">
<TextBlock Text="Реєстрація" FontSize="22" FontWeight="Bold"
Foreground="#1e293b"/>
<StackPanel Spacing="4">
<TextBlock Text="Ім'я" FontSize="13" FontWeight="SemiBold" Foreground="#475569"/>
<TextBox Padding="10,7" Text="Іванко Петренко"
BorderBrush="#cbd5e1" BorderThickness="1"/>
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Text="Email" FontSize="13" FontWeight="SemiBold" Foreground="#475569"/>
<TextBox Padding="10,7" Text="ivan@example.com"
BorderBrush="#cbd5e1" BorderThickness="1"/>
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Text="Пароль" FontSize="13" FontWeight="SemiBold" Foreground="#475569"/>
<PasswordBox Padding="10,7" BorderBrush="#cbd5e1" BorderThickness="1"/>
</StackPanel>
<CheckBox Content="Погоджуюся з умовами використання"
Foreground="#64748b" FontSize="12"/>
<Button Content="Зареєструватися" Padding="0,10"
Background="#2563eb" Foreground="White" FontWeight="SemiBold"
HorizontalContentAlignment="Center"/>
<TextBlock HorizontalAlignment="Center" FontSize="12" Foreground="#94a3b8">
<Run Text="Вже є акаунт? "/>
<Run Text="Увійти" Foreground="#2563eb" TextDecorations="Underline"/>
</TextBlock>
</StackPanel>
</Border>
StackPanel ідеальний для:
✅ Вертикальні списки: меню, списки налаштувань, чекбокси, форми з вертикальним потоком
✅ Горизонтальні панелі: toolbar, рядок кнопок, breadcrumbs, tabs-рядок
✅ Фіксований вміст: коли кількість елементів невелика і не змінюється
✅ Як внутрішній контейнер: всередині Grid-комірок, Border, ScrollViewer
❌ Не підходить для:
Grid)ListBox або ItemsControl з VirtualizingStackPanel)WrapPanel — це StackPanel, якому дозволили "переносити рядок". Якщо при горизонтальному вкладанні наступний елемент не вміщається у ширину — він переходить на новий рядок. При вертикальному — на новий стовпець.
<!-- Горизонтальний WrapPanel (за замовчуванням) -->
<WrapPanel>
<Button Content="Елемент А" Margin="4" Padding="12,8"/>
<Button Content="Елемент Б" Margin="4" Padding="12,8"/>
<Button Content="Елемент В" Margin="4" Padding="12,8"/>
<!-- Якщо В не вміщається — переноситься на новий рядок -->
<Button Content="Елемент Г" Margin="4" Padding="12,8"/>
<Button Content="Елемент Д" Margin="4" Padding="12,8"/>
</WrapPanel>
Ключова відмінність від StackPanel:
StackPanel ніколи не переносить — елементи просто виходять за межі і обрізаються (або розтягують панель нескінченно)WrapPanel відстежує доступну ширину і переносить при нестачіLoading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<WrapPanel Margin="16">
<Button Content="JavaScript" Margin="4" Padding="10,6" Background="#f7df1e" Foreground="#000"/>
<Button Content="TypeScript" Margin="4" Padding="10,6" Background="#3178c6" Foreground="White"/>
<Button Content="Python" Margin="4" Padding="10,6" Background="#3776ab" Foreground="White"/>
<Button Content="C#" Margin="4" Padding="10,6" Background="#512bd4" Foreground="White"/>
<Button Content="Rust" Margin="4" Padding="10,6" Background="#ce422b" Foreground="White"/>
<Button Content="Go" Margin="4" Padding="10,6" Background="#00add8" Foreground="White"/>
<Button Content="Java" Margin="4" Padding="10,6" Background="#f89820" Foreground="White"/>
<Button Content="Kotlin" Margin="4" Padding="10,6" Background="#7f52ff" Foreground="White"/>
<Button Content="Swift" Margin="4" Padding="10,6" Background="#ff6347" Foreground="White"/>
<Button Content="Ruby" Margin="4" Padding="10,6" Background="#cc342d" Foreground="White"/>
<Button Content="PHP" Margin="4" Padding="10,6" Background="#777bb4" Foreground="White"/>
<Button Content="Dart" Margin="4" Padding="10,6" Background="#0175c2" Foreground="White"/>
</WrapPanel>
ItemWidth та ItemHeight: рівномірна сіткаЗа замовчуванням кожен елемент займає стільки місця, скільки йому треба — тому елементи у WrapPanel можуть мати різну ширину. Щоб зробити рівномірну сітку — використовуйте ItemWidth та ItemHeight:
<!-- Всі елементи матимуть ширину 120 і висоту 80 -->
<WrapPanel ItemWidth="120" ItemHeight="80">
<Border Background="#3b82f6" Margin="4">
<TextBlock Text="Картка 1" HorizontalAlignment="Center"
VerticalAlignment="Center" Foreground="White"/>
</Border>
<Border Background="#8b5cf6" Margin="4">
<TextBlock Text="Картка 2" HorizontalAlignment="Center"
VerticalAlignment="Center" Foreground="White"/>
</Border>
<Border Background="#10b981" Margin="4">
<TextBlock Text="Картка 3" HorizontalAlignment="Center"
VerticalAlignment="Center" Foreground="White"/>
</Border>
<!-- ... -->
</WrapPanel>
Коли заданий ItemWidth — WrapPanel ділить доступну ширину на ItemWidth і визначає, скільки елементів поміщається у рядок. Решта переноситься. Отримується поведінка подібна до CSS display: flex; flex-wrap: wrap;.
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<WrapPanel ItemWidth="130" ItemHeight="100" Margin="12">
<Border Margin="4" Background="#dbeafe" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="📁" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Документи" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
<Border Margin="4" Background="#fce7f3" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="🖼️" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Зображення" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
<Border Margin="4" Background="#dcfce7" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="🎵" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Музика" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
<Border Margin="4" Background="#fef9c3" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="🎬" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Відео" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
<Border Margin="4" Background="#ede9fe" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="📦" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Архіви" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
<Border Margin="4" Background="#fee2e2" CornerRadius="6">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="4">
<TextBlock Text="⚙️" FontSize="24" HorizontalAlignment="Center"/>
<TextBlock Text="Система" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Border>
</WrapPanel>
Orientation="Vertical" вкладає елементи зверху вниз і переносить на новий стовпець при нестачі висоти:
<WrapPanel Orientation="Vertical" Height="200">
<Button Content="А" Margin="4" Padding="10,8"/>
<Button Content="Б" Margin="4" Padding="10,8"/>
<Button Content="В" Margin="4" Padding="10,8"/>
<!-- При нестачі висоти — переноситься у другий стовпець -->
<Button Content="Г" Margin="4" Padding="10,8"/>
<Button Content="Д" Margin="4" Padding="10,8"/>
</WrapPanel>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<WrapPanel Orientation="Vertical" Height="160" Margin="16">
<Border Background="#93c5fd" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Альфа" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#86efac" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Бета" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#fca5a5" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Гамма" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#fdba74" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Дельта" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#c4b5fd" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Епсилон" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#67e8f9" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Дзета" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#a3e635" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Ета" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
<Border Background="#fb923c" Width="80" Height="40" Margin="4" CornerRadius="4">
<TextBlock Text="Тета" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11"/>
</Border>
</WrapPanel>
WrapPanel часто використовують в парі зі ScrollViewer. Так виходить адаптивна галерея: при зменшенні вікна — більше рядків але скролл компенсує:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<WrapPanel Margin="8">
<!-- Тут може бути 100 карток/зображень -->
<Border Width="160" Height="120" Margin="6" Background="#e2e8f0" CornerRadius="8">
<TextBlock Text="Фото 1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<!-- ... -->
</WrapPanel>
</ScrollViewer>
WrapPanel — не найефективніший для великих списків. При 1000+ елементів краще використовувати ItemsControl з WrapPanel як ItemsPanel — тоді WPF застосує віртуалізацію (тільки видимі елементи існують у пам'яті). Але для UI-компонентів (кнопки тегів, набори іконок, менеджер файлів) — WrapPanel абсолютно підходить.✅ Набори тегів або категорій: кнопки-теги, фільтри, чіпи
✅ Файловий менеджер / галерея: іконки файлів що заповнюють вікно
✅ Адаптивні панелі кнопок: toolbar що переносить кнопки при вузькому вікні
✅ Будь-яке розміщення "зліва направо з переносом"
❌ Не підходить для:
Grid)UniformGrid або Grid)DockPanel — панель для побудови класичного інтерфейсу настільного застосунку: меню зверху, панель статусу знизу, дерево/навігація зліва, основний вміст у центрі. Цей патерн настільки поширений, що має власну назву — Shell Layout.
Принцип роботи: кожен дочірній елемент "прикріплюється" до однієї зі сторін через Attached Property DockPanel.Dock. Значення: Top, Bottom, Left, Right. Після всіх прикріплених — останній дочірній займає весь решта простору. Ця поведінка регулюється LastChildFill (за замовчуванням True).
<DockPanel>
<Menu DockPanel.Dock="Top"/> <!-- прикріплено зверху -->
<StatusBar DockPanel.Dock="Bottom"/> <!-- прикріплено знизу -->
<TreeView DockPanel.Dock="Left" Width="200"/> <!-- прикріплено зліва -->
<TextBox AcceptsReturn="True"/> <!-- LastChildFill: займає весь центр -->
</DockPanel>
Порядок оголошення має значення: DockPanel обробляє елементи зверху вниз по XML. Кожен наступний отримує залишок простору після попередніх.
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<DockPanel>
<Menu DockPanel.Dock="Top" Background="#1e293b" Foreground="White" Padding="4,2">
<MenuItem Header="📁 Файл" Foreground="White"/>
<MenuItem Header="✏️ Правка" Foreground="White"/>
<MenuItem Header="👁️ Вигляд" Foreground="White"/>
</Menu>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"
Background="#f1f5f9" Padding="8,4" Spacing="4">
<Button Content="📄" Padding="8,4"/>
<Button Content="💾" Padding="8,4"/>
<Separator Width="1" Background="#cbd5e1" Margin="4,0"/>
<Button Content="↩️" Padding="8,4"/>
<Button Content="↪️" Padding="8,4"/>
</StackPanel>
<StatusBar DockPanel.Dock="Bottom" Background="#1e293b" Padding="8,4">
<StatusBarItem>
<TextBlock Text="✅ Готово | Рядок 1 | UTF-8" Foreground="White" FontSize="12"/>
</StatusBarItem>
</StatusBar>
<Border DockPanel.Dock="Left" Width="180" Background="#f8fafc"
BorderBrush="#e2e8f0" BorderThickness="0,0,1,0">
<StackPanel Margin="8" Spacing="2">
<TextBlock Text="ПРОВІДНИК" FontSize="11" FontWeight="Bold" Foreground="#94a3b8" Margin="4,8,4,4"/>
<Button Content="📁 src" HorizontalContentAlignment="Left" Padding="8,4" Background="Transparent"/>
<Button Content=" 📄 App.xaml" HorizontalContentAlignment="Left" Padding="8,4" Background="#e0f2fe" FontSize="12"/>
<Button Content=" 📄 MainWindow.xaml" HorizontalContentAlignment="Left" Padding="8,4" Background="Transparent" FontSize="12"/>
<Button Content="📁 Resources" HorizontalContentAlignment="Left" Padding="8,4" Background="Transparent"/>
</StackPanel>
</Border>
<TextBox AcceptsReturn="True" Padding="16" Background="White"
BorderThickness="0" FontFamily="Consolas" FontSize="13"
Text="// Тут ваш контент
// Займає всю решту площі
// завдяки LastChildFill=True"/>
</DockPanel>
Кожен елемент "відрізає" свою частину від загального простору. Наступний отримує залишок:
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<DockPanel Width="420" Height="260" Margin="16">
<Border DockPanel.Dock="Top" Height="40" Background="#3b82f6">
<TextBlock Text="Top (40px)" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="White" FontWeight="Bold"/>
</Border>
<Border DockPanel.Dock="Bottom" Height="30" Background="#ef4444">
<TextBlock Text="Bottom (30px)" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="White" FontWeight="Bold"/>
</Border>
<Border DockPanel.Dock="Left" Width="90" Background="#10b981">
<TextBlock Text="Left\n(90px)" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="White" FontWeight="Bold" TextAlignment="Center"/>
</Border>
<Border DockPanel.Dock="Right" Width="70" Background="#f59e0b">
<TextBlock Text="Right\n(70px)" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="White" FontWeight="Bold" TextAlignment="Center"/>
</Border>
<Border Background="#6366f1">
<TextBlock Text="Fill
(весь залишок)" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="White" FontWeight="Bold" TextAlignment="Center"/>
</Border>
</DockPanel>
Один Dock може бути у кількох елементів — вони вишиковуються по черзі в тому ж напрямку:
<DockPanel>
<!-- Обидва зверху: Menu, потім Toolbar під ним -->
<Menu DockPanel.Dock="Top"/>
<ToolBar DockPanel.Dock="Top"/>
<!-- Bottom: перший Bottom буде ближче до краю, другий — вище нього -->
<StatusBar DockPanel.Dock="Bottom"/>
<FindBar DockPanel.Dock="Bottom"/>
<TextBox/>
</DockPanel>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<DockPanel Height="300" Margin="16">
<Border DockPanel.Dock="Top" Height="36" Background="#1e40af">
<TextBlock Text="Menu Bar" VerticalAlignment="Center" Margin="12,0" Foreground="White" FontWeight="Bold"/>
</Border>
<Border DockPanel.Dock="Top" Height="32" Background="#3b82f6">
<TextBlock Text="Toolbar" VerticalAlignment="Center" Margin="12,0" Foreground="White"/>
</Border>
<Border DockPanel.Dock="Bottom" Height="24" Background="#1e3a8a">
<TextBlock Text="Status Bar (самий низ)" VerticalAlignment="Center" Margin="8,0" Foreground="White" FontSize="11"/>
</Border>
<Border DockPanel.Dock="Bottom" Height="32" Background="#2563eb">
<TextBlock Text="Find Bar (над Status)" VerticalAlignment="Center" Margin="8,0" Foreground="White" FontSize="12"/>
</Border>
<Border DockPanel.Dock="Left" Width="120" Background="#f0fdf4">
<TextBlock Text="Nav Tree" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#166534" FontWeight="Bold"/>
</Border>
<Border DockPanel.Dock="Left" Width="60" Background="#dcfce7">
<TextBlock Text="Mini" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#166534" FontSize="11"/>
</Border>
<Border Background="#f8fafc">
<TextBlock Text="Content (Fill)" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#64748b"/>
</Border>
</DockPanel>
LastChildFill="False"Якщо не потрібно, щоб останній елемент займав весь центр:
<!-- Всі елементи з явним Dock: центру немає -->
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Top" Content="Верх"/>
<Button DockPanel.Dock="Left" Content="Ліво"/>
<Button DockPanel.Dock="Right" Content="Право"/>
<!-- Без LastChildFill останній також просто прикріплюється зверху -->
<Button DockPanel.Dock="Top" Content="Ще верх"/>
</DockPanel>
DockPanel є одним з рідкісних випадків у WPF, де порядок дочірніх у XAML прямо впливає на результат. StackPanel і WrapPanel — теж залежать від порядку, але у DockPanel ця залежність найбільш драматична: переставити Menu нижче за StatusBar в XAML — і UI зламається.StackPanel
Для: Вертикальних форм, горизонтальних toolbar, вкладених рядків меню. Елементи займають свій DesiredSize по основній осі і 100% по поперечній.
Використовуйте коли: Потрібен простий лінійний потік елементів без переносу і без прив'язки до сторін.
WrapPanel
Для: Тегів, фільтрів, файлових іконок, адаптивних наборів кнопок. ItemWidth/ItemHeight для рівних клітинок.
Використовуйте коли: Елументи мають переноситися на нові рядки автоматично при нестачі місця.
DockPanel
Для: Shell Layout (Menu + Toolbar + Sidebar + Content + StatusBar). Порядок у XAML = порядок розміщення.
Використовуйте коли: Потрібна типова оболонка застосунку або будь-який layout з "периферійними" зонами та центральним вмістом.
| StackPanel | WrapPanel | DockPanel | |
|---|---|---|---|
| Авто-перенос | ❌ | ✅ | ❌ |
| Рівномірна сітка | ❌ | ItemWidth | ❌ |
| Центральний Fill | ❌ | ❌ | ✅ |
| Вкладення | ✅ | рідко | ✅ |
Завдання: Побудуйте горизонтальний toolbar через StackPanel Orientation="Horizontal".
Вимоги:
Spacing="4", вертикальний Separator між групами (після "Зберегти")#1e293b, кнопки прозорі з Foreground="White"Поглиблення: Додайте другий горизонтальний StackPanel-рядок вкладок файлів.
Перевірка: Toolbar виглядає як у реальному редакторі — без видимих меж кнопок.
Завдання: Класичний "оболонковий" інтерфейс через DockPanel.
Обов'язкові зони:
DockPanel.Dock="Top" — Menu (горизонтальний StackPanel з TextBlock)DockPanel.Dock="Top" — Toolbar (кнопки)DockPanel.Dock="Bottom" — StatusBarDockPanel.Dock="Left" Width="200" — Sidebar з навігаційними кнопкамиПоглиблення: DockPanel.Dock="Right" Width="160" — панель властивостей.
Перевірка: Змінення розміру вікна → Zone зберігають свою ширину/висоту, Fill адаптується.
Завдання: Адаптивна галерея ScrollViewer → WrapPanel + адаптивні фільтри.
Вимоги:
ScrollViewer → WrapPanel ItemWidth="180" ItemHeight="140" — 12+ карток файлівBorder CornerRadius="8", emoji-іконка (FontSize=32), назва файлуBackground для різних типів файлівDockPanel): WrapPanel з кнопками-тегами "Всі", "Зображення", "Відео", "Документи"Перевірка: При вузькому вікні — менше стовпців (автоматично). ScrollViewer компенсує висоту. Фільтри-теги самі переносяться при нестачі ширини.
Розширення розмітки XAML (Markup Extensions)
Вивчаємо механізм фігурних дужок {…} у XAML: MarkupExtension, ProvideValue, вбудовані x:Static/x:Type/x:Null/x:Array/Binding, перший погляд на Binding та створення Custom Markup Extension.
Grid, Canvas, UniformGrid
Вивчаємо Grid — найпотужнішу панель WPF: типи розмірів Auto/**/fixed, Grid.Row/Column, RowSpan/ColumnSpan, SharedSizeGroup. Розбираємо Canvas та UniformGrid.