Попередні статті про панелі (StackPanel, WrapPanel, DockPanel, Grid) охопили основний "каркас" інтерфейсу. Але WPF пропонує набір додаткових інструментів, без яких реальний UI неможливий: коректні відступи, вирівнювання, обмеження розмірів, прокручування, масштабування та інтерактивне перетворення зон.
Ця стаття — про деталі, що відрізняють "робочий" інтерфейс від "гарного" інтерфейсу.
Margin — це простір навколо елемента, між його зовнішнім краєм і сусідніми елементами або краями батьківського контейнера. Аналог margin у CSS.
WPF підтримує три варіанти запису:
<!-- 1. Одне число: однаковий відступ з усіх сторін -->
<Button Margin="8" Content="8px з усіх сторін"/>
<!-- 2. Два числа: horizontal, vertical (Left+Right, Top+Bottom) -->
<Button Margin="16,8" Content="16pxліво/право, 8px верх/низ"/>
<!-- 3. Чотири числа: Left, Top, Right, Bottom -->
<Button Margin="12,8,12,4" Content="12 ліво, 8 верх, 12 право, 4 низ"/>
Left, Top, Right, Bottom — відрізняється від CSS де порядок Top, Right, Bottom, Left (за годинниковою). Це часта помилка навіть у досвідчених WPF-розробників що прийшли з веб.Margin — це Thickness — структура з чотирма полями. У коді:
// Еквіваленти:
button.Margin = new Thickness(8); // "8"
button.Margin = new Thickness(16, 8, 16, 8); // "16,8"
button.Margin = new Thickness(12, 8, 12, 4); // "12,8,12,4"
Margin елемента займає простір у батьківському контейнері — зменшує доступний простір для елемента:
<StackPanel>
<Button Margin="8" Content="Кнопка 1"/> <!-- 8px відступ з усіх сторін -->
<Button Margin="8" Content="Кнопка 2"/> <!-- Відступ між кнопками: 8 + 8 = 16px -->
<!-- Ось чому Spacing у StackPanel зручніший: не подвоює відступи -->
</StackPanel>
Краще використовувати Spacing у StackPanel для відступів між елементами і Margin для відступів від країв контейнера:
<!-- Правильно: Spacing між елементами, Margin ззовні -->
<StackPanel Spacing="8" Margin="16">
<Button Content="Кнопка 1"/>
<Button Content="Кнопка 2"/>
<Button Content="Кнопка 3"/>
</StackPanel>
Padding — простір всередині контролу, між його краями і вмістом. Не всі елементи мають Padding (наприклад, TextBlock підтримує, Rectangle — ні).
Той самий синтаксис що Margin:
<Button Padding="20,8" Content="Більша кнопка"/>
<TextBox Padding="12,6" Text="Текст з відступами від країв"/>
<Border Padding="16">
<TextBlock Text="Контент з відступом 16px від кожного краю Border"/>
</Border>
┌─────────────── ParentContainer ─────────────────┐
│ ↑ Margin.Top │
│ ┌─────┴──────── Element ──────────────┐ │
│ │ ↑ Padding.Top │ │
│M │ ┌───┴────── Content ─────┐ │P M │
│. │ │ │ │. . │
│L │ └────────────────────────-┘ │R R │
│ │ ↓ Padding.Bottom │ │
│ └───────────────────────────────────┘ │
│ ↓ Margin.Bottom │
└────────────────────────────────────────────────┘
Margin — простір зовні елемента (між елементом і його сусідами)Padding — простір всередині кордону елемента (між кордоном і вмістом)Background заповнює Padding-область (тобто фон видно за відступами)Border малюється поверх Background, але до PaddingLoading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<StackPanel Margin="16" Spacing="16">
<!-- Margin: зовнішній відступ від сусідів -->
<TextBlock Text="Приклад 1: Margin (зовнішній відступ)" FontWeight="SemiBold" Foreground="#374151"/>
<Grid Background="#e0e7ff">
<Button Margin="24" Content="Button з Margin=24"
Background="#4f46e5" Foreground="White" Padding="8,4"/>
</Grid>
<!-- Padding: внутрішній відступ від країв до вмісту -->
<TextBlock Text="Приклад 2: Padding (внутрішній відступ)" FontWeight="SemiBold" Foreground="#374151"/>
<Grid Background="#d1fae5">
<Button Padding="32,16" Content="Button з Padding=32,16"
Background="#059669" Foreground="White"/>
</Grid>
<!-- Обидва разом -->
<TextBlock Text="Приклад 3: Margin + Padding разом" FontWeight="SemiBold" Foreground="#374151"/>
<StackPanel Background="#fce7f3" Spacing="0">
<Border Margin="16" Padding="16" Background="#f9a8d4" BorderBrush="#ec4899" BorderThickness="2" CornerRadius="8">
<TextBlock Text="Border: Margin=16 (зовні у рожевій зоні), Padding=16 (всередині між рамкою і текстом)"
TextWrapping="Wrap" Foreground="#831843"/>
</Border>
</StackPanel>
<!-- Padding впливає на Area фону -->
<TextBlock Text="Приклад 4: Background заповнює Padding-область" FontWeight="SemiBold" Foreground="#374151"/>
<TextBlock Text="Текст з Padding та фоном — фон видно за відступами"
Padding="20,12" Background="#fef3c7" Foreground="#92400e"
FontSize="14"/>
</StackPanel>
Кожен елемент у WPF має дві властивості вирівнювання:
HorizontalAlignment — горизонтальне (Left, Center, Right, Stretch)VerticalAlignment — вертикальне (Top, Center, Bottom, Stretch)За замовчуванням — Stretch: елемент займає весь доступний простір у своєму напрямку.
<Grid Width="400" Height="200">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- Без вирівнювання: Stretch (за замовчуванням) -->
<Button Grid.Row="0" Grid.Column="0" Content="Stretch" Margin="4"/>
<!-- Left: прилипає до лівого краю комірки -->
<Button Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
Content="Left" Margin="4"/>
<!-- Center: по центру комірки -->
<Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center"
Content="Center" Margin="4"/>
<!-- Right: прилипає до правого краю -->
<Button Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right"
Content="Right" Margin="4"/>
</Grid>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Grid ShowGridLines="True" Margin="8" Height="280">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- Заголовки рядків -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Stretch" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11" Foreground="#6b7280"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Left/Top" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11" Foreground="#6b7280"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11" Foreground="#6b7280"/>
<TextBlock Grid.Row="0" Grid.Column="3" Text="Right/Bottom" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="11" Foreground="#6b7280"/>
<!-- Рядок 2: HorizontalAlignment -->
<Border Grid.Row="1" Grid.Column="0" Background="#2563eb" Margin="4">
<TextBlock Text="H:Stretch" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="1" Grid.Column="1" Background="#059669" Margin="4" HorizontalAlignment="Left" Width="60">
<TextBlock Text="H:Left" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="1" Grid.Column="2" Background="#7c3aed" Margin="4" HorizontalAlignment="Center" Width="60">
<TextBlock Text="H:Center" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="1" Grid.Column="3" Background="#dc2626" Margin="4" HorizontalAlignment="Right" Width="60">
<TextBlock Text="H:Right" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<!-- Рядок 3: VerticalAlignment -->
<Border Grid.Row="2" Grid.Column="0" Background="#0369a1" Margin="4">
<TextBlock Text="V:Stretch" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="2" Grid.Column="1" Background="#065f46" Margin="4" VerticalAlignment="Top" Height="30">
<TextBlock Text="V:Top" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="2" Grid.Column="2" Background="#5b21b6" Margin="4" VerticalAlignment="Center" Height="30">
<TextBlock Text="V:Center" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
<Border Grid.Row="2" Grid.Column="3" Background="#991b1b" Margin="4" VerticalAlignment="Bottom" Height="30">
<TextBlock Text="V:Bottom" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="10"/>
</Border>
</Grid>
Це вирівнювання вмісту всередині контролу — наприклад, тексту всередині Button або ListBoxItem. Відрізняється від HorizontalAlignment контролу відносно батьківського контейнера:
<!-- HorizontalAlignment: кнопка у правій частині Grid -->
<Button HorizontalAlignment="Right" Content="Праворуч у Grid"/>
<!-- HorizontalContentAlignment: текст у правій частині кнопки -->
<Button Width="200" HorizontalContentAlignment="Right" Content="Текст у правій частині кнопки"/>
<!-- Поєднання: кнопка по центру Grid, текст по лівому краю всередині кнопки -->
<Button HorizontalAlignment="Center" Width="200"
HorizontalContentAlignment="Left" Padding="12,0"
Content="← Текст зліва у кнопці"/>
Обмеження розмірів — важливий інструмент для адаптивних інтерфейсів. Без обмежень елементи можуть бути занадто малими або занадто великими.
<!-- TextBox що розтягується, але не менше 100px і не більше 400px -->
<TextBox MinWidth="100" MaxWidth="400" Width="Auto"
HorizontalAlignment="Stretch" Text="Гнучке текстове поле"/>
<!-- Кнопки мають мінімальну ширину 80px (однаковий вигляд) -->
<StackPanel Orientation="Horizontal" Spacing="8">
<Button MinWidth="80" Content="OK"/>
<Button MinWidth="80" Content="Скасувати"/>
<Button MinWidth="80" Content="Застосувати"/>
</StackPanel>
<!-- Dropdown-список не вище 300px -->
<ComboBox MaxHeight="300">
<!-- ItemsSource або Items -->
</ComboBox>
MinWidth/MaxWidth взаємодіють із Measure Pass:
DesiredSize — але з урахуванням Min/Max обмеженьMinWidth — елемент усе одно займе MinWidth (може виступати за межі батьківського)MaxWidth — елемент обмежується MaxWidthLoading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<StackPanel Margin="16" Spacing="12" MaxWidth="480" HorizontalAlignment="Left">
<TextBlock Text="Адаптивна форма (спробуйте змінити ширину вікна)"
FontWeight="Bold" Foreground="#1e293b"/>
<!-- Шукати: мінімум 120px, максимум повна ширина -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Padding="10,7" MinWidth="120"
Text="Пошук..." BorderBrush="#cbd5e1"/>
<Button Grid.Column="1" Content="🔍" Padding="10,7"
Background="#2563eb" Foreground="White" Margin="8,0,0,0"/>
</Grid>
<!-- Кнопки з однаковою мінімальною шириною -->
<TextBlock Text="Кнопки дій (MinWidth=100 для однаковості):"
Foreground="#64748b" FontSize="13"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<Button MinWidth="100" Content="Зберегти" Background="#2563eb" Foreground="White" Padding="8,6"/>
<Button MinWidth="100" Content="OK" Padding="8,6"/>
<Button MinWidth="100" Content="Скасувати" Padding="8,6"/>
</StackPanel>
<!-- TextBox з MaxWidth: не стає ширшим ніж потрібно -->
<TextBlock Text="Поле Email (MaxWidth=280):" Foreground="#64748b" FontSize="13"/>
<TextBox MaxWidth="280" HorizontalAlignment="Left"
Padding="10,7" Text="user@example.com" BorderBrush="#cbd5e1"/>
</StackPanel>
ScrollViewer — контейнер-обгортка, що додає смуги прокрутки до свого вмісту. Коли вміст більший за видиму область — з'являється ScrollBar.
<!-- Базовий ScrollViewer: вертикальна прокрутка за замовчуванням -->
<ScrollViewer>
<StackPanel>
<!-- Bagato elementiv -->
</StackPanel>
</ScrollViewer>
VerticalScrollBarVisibility і HorizontalScrollBarVisibility мають чотири значення:
| Значення | Поведінка |
|---|---|
Auto | Смуга прокрутки з'являється тільки коли вміст не вміщується (за замовчуванням для Vertical) |
Visible | Смуга завжди видима (навіть якщо прокрутки немає) |
Hidden | Смуга прихована, але вміст все одно прокручується (колесо миші) |
Disabled | Смуга прихована І контент обрізається (прокрутки немає) |
За замовчуванням у ScrollViewer:
VerticalScrollBarVisibility = Auto (вертикальна прокрутка є)HorizontalScrollBarVisibility = Disabled (горизонтальна прокрутка вимкнена!)<!-- Вертикальна: Auto (з'являється за потребою) -->
<ScrollViewer VerticalScrollBarVisibility="Auto">...</ScrollViewer>
<!-- Обидва напрямки -->
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<Image Width="2000" Height="3000" Source="large-map.jpg"/>
</ScrollViewer>
<!-- Завжди видима смуга (виглядає стабільніше) -->
<ScrollViewer VerticalScrollBarVisibility="Visible">...</ScrollViewer>
Найпоширеніша помилка початківця:
<!-- ПРОБЛЕМА: ScrollViewer не прокручується! -->
<StackPanel>
<ScrollViewer> <!-- ← ScrollViewer отримує нескінченну висоту! -->
<ListBox ItemsSource="{Binding Items}"/>
</ScrollViewer>
</StackPanel>
Причина: StackPanel надає своїм дочірнім елементам нескінченний простір по вертикалі (Measure Pass повертає Infinity). Тому ScrollViewer отримує нескінченну висоту, його вміст теж отримує нескінченну висоту і ніколи не "переповнюється" — прокрутки не виникає.
Рішення 1: Дати ScrollViewer фіксовану висоту:
<StackPanel>
<ScrollViewer Height="300">
<ListBox ItemsSource="{Binding Items}"/>
</ScrollViewer>
</StackPanel>
Рішення 2: Замінити StackPanel на Grid з *-рядком (Grid надає скінченну висоту):
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Заголовок -->
<RowDefinition Height="*"/> <!-- ScrollViewer отримує скінченну висоту! -->
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Список"/>
<ScrollViewer Grid.Row="1">
<ListBox ItemsSource="{Binding Items}"/>
</ScrollViewer>
</Grid>
Рішення 3: Загорнути весь StackPanel у ScrollViewer (часто найлогічніше):
<ScrollViewer>
<StackPanel>
<TextBlock Text="Заголовок"/>
<ListBox Height="300" ItemsSource="{Binding Items}"/>
</StackPanel>
</ScrollViewer>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Grid Margin="16" Height="320">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Ліва панель -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Auto (смуга за потребою)"
FontWeight="SemiBold" Foreground="#1e293b" Margin="0,0,0,8"/>
<ScrollViewer Grid.Row="1" Grid.Column="0" VerticalScrollBarVisibility="Auto"
Background="#f8fafc" BorderBrush="#e2e8f0" BorderThickness="1">
<StackPanel Spacing="0">
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="📧 Листи" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1" Background="#eff6ff">
<TextBlock Text="📁 Вхідні" Foreground="#2563eb" FontWeight="SemiBold"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="📤 Надіслані" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="⭐ Важливі" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="🗑️ Кошик" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="📂 Архів" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="🏷️ Теги" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="📌 Закріплені" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="🔔 Сповіщення" Foreground="#374151"/>
</Border>
<Border Padding="12,8">
<TextBlock Text="⚙️ Налаштування" Foreground="#374151"/>
</Border>
</StackPanel>
</ScrollViewer>
<!-- Права панель -->
<TextBlock Grid.Row="0" Grid.Column="2" Text="Visible (смуга завжди)"
FontWeight="SemiBold" Foreground="#1e293b" Margin="0,0,0,8"/>
<ScrollViewer Grid.Row="1" Grid.Column="2" VerticalScrollBarVisibility="Visible"
Background="#f8fafc" BorderBrush="#e2e8f0" BorderThickness="1">
<StackPanel Spacing="0">
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="Рядок 1" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="Рядок 2" Foreground="#374151"/>
</Border>
<Border Padding="12,8" BorderBrush="#f1f5f9" BorderThickness="0,0,0,1">
<TextBlock Text="Рядок 3" Foreground="#374151"/>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
ViewBox — контейнер, що масштабує свій єдиний дочірній елемент, щоб заповнити доступний простір. Він не змінює логічний розмір вмісту — тільки візуально трансформує через ScaleTransform.
<Viewbox Width="200" Height="100">
<!-- Вміст Viewbox: кнопка 80×30 → буде масштабована до 200×100 -->
<Button Width="80" Height="30" Content="Масштабована кнопка"/>
</Viewbox>
Stretch визначає як саме вміст масштабується:
<!-- Uniform: зберігає пропорції (чорні смуги якщо пропорції різні) -->
<Viewbox Stretch="Uniform" Width="300" Height="100">
<Button Width="200" Height="200" Content="Квадрат у прямокутнику"/>
</Viewbox>
<!-- Fill: розтягує без збереження пропорцій (все заповнено, але може деформуватись) -->
<Viewbox Stretch="Fill" Width="300" Height="100">
<Button Width="200" Height="200" Content="Деформований"/>
</Viewbox>
<!-- UniformToFill: зберігає пропорції, обрізає (все заповнено, нічого не деформовано) -->
<Viewbox Stretch="UniformToFill" Width="300" Height="100">
<TextBlock Text="Обрізаний але не деформований" FontSize="24"/>
</Viewbox>
<!-- None: не масштабує (натуральний розмір) -->
<Viewbox Stretch="None" Width="300" Height="100">
<Button Width="200" Height="200" Content="Натуральний (може виступати)"/>
</Viewbox>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Grid Margin="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Uniform" HorizontalAlignment="Center" FontSize="11" Foreground="#6b7280" Margin="0,0,0,4"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Fill" HorizontalAlignment="Center" FontSize="11" Foreground="#6b7280" Margin="0,0,0,4"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="UniformToFill" HorizontalAlignment="Center" FontSize="11" Foreground="#6b7280" Margin="0,0,0,4"/>
<TextBlock Grid.Row="0" Grid.Column="3" Text="None" HorizontalAlignment="Center" FontSize="11" Foreground="#6b7280" Margin="0,0,0,4"/>
<Border Grid.Row="1" Grid.Column="0" Background="#eff6ff" Margin="4" ClipToBounds="True">
<Viewbox Stretch="Uniform">
<StackPanel Orientation="Horizontal" Spacing="4" Width="100" Height="100">
<TextBlock Text="🎯" FontSize="48"/>
</StackPanel>
</Viewbox>
</Border>
<Border Grid.Row="1" Grid.Column="1" Background="#f0fdf4" Margin="4" ClipToBounds="True">
<Viewbox Stretch="Fill">
<StackPanel Orientation="Horizontal" Spacing="4" Width="100" Height="100">
<TextBlock Text="🎯" FontSize="48"/>
</StackPanel>
</Viewbox>
</Border>
<Border Grid.Row="1" Grid.Column="2" Background="#fdf4ff" Margin="4" ClipToBounds="True">
<Viewbox Stretch="UniformToFill">
<StackPanel Orientation="Horizontal" Spacing="4" Width="100" Height="100">
<TextBlock Text="🎯" FontSize="48"/>
</StackPanel>
</Viewbox>
</Border>
<Border Grid.Row="1" Grid.Column="3" Background="#fff7ed" Margin="4" ClipToBounds="True">
<Viewbox Stretch="None">
<TextBlock Text="🎯" FontSize="48"/>
</Viewbox>
</Border>
</Grid>
Border — один з найуживаніших елементів у WPF. Він надає чотири візуальні можливості: рамку (BorderBrush/BorderThickness), фон (Background), закруглені кути (CornerRadius) та внутрішні відступи (Padding).
<Border Background="#f8fafc"
BorderBrush="#e2e8f0"
BorderThickness="1"
CornerRadius="8"
Padding="16">
<!-- Вміст: будь-який один елемент -->
<TextBlock Text="Картка з рамкою, фоном і закругленнями"/>
</Border>
Border — одно-дочірній контейнер. Щоб помістити кілька елементів — вкладіть StackPanel або Grid:
<Border Background="White" BorderBrush="#e2e8f0" BorderThickness="1"
CornerRadius="12" Padding="20">
<StackPanel Spacing="8">
<TextBlock Text="Заголовок картки" FontSize="16" FontWeight="Bold"/>
<TextBlock Text="Опис картки з кількома рядками тексту" TextWrapping="Wrap"/>
<Button Content="Дія" HorizontalAlignment="Right"/>
</StackPanel>
</Border>
<!-- Однакові всі 4 кути -->
<Border CornerRadius="8" Background="#2563eb" Padding="12,6">
<TextBlock Text="Всі 8px" Foreground="White"/>
</Border>
<!-- Різні кути: TopLeft, TopRight, BottomRight, BottomLeft -->
<Border CornerRadius="16,0,16,0" Background="#7c3aed" Padding="12,6">
<TextBlock Text="Змінні кути" Foreground="White"/>
</Border>
<!-- Таблетка (pill-форма): велике заокруглення для повністю круглих країв -->
<Border CornerRadius="100" Background="#059669" Padding="16,8">
<TextBlock Text="Pill badge" Foreground="White"/>
</Border>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<StackPanel Margin="16" Spacing="16">
<!-- Класична картка -->
<Border Background="White" BorderBrush="#e2e8f0" BorderThickness="1"
CornerRadius="10" Padding="16">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Нове замовлення #1847" FontWeight="SemiBold" Foreground="#1e293b"/>
<TextBlock Text="Іван Петренко • 3 товари • ₴2,340" FontSize="13" Foreground="#64748b"/>
</StackPanel>
<Border Grid.Column="1" Background="#dcfce7" CornerRadius="6" Padding="8,4"
VerticalAlignment="Center">
<TextBlock Text="✅ Оплачено" Foreground="#166534" FontSize="12" FontWeight="SemiBold"/>
</Border>
</Grid>
</Border>
<!-- Кольорова картка з лівою акцентною лінією -->
<Border Background="#eff6ff" CornerRadius="8" Padding="0"
BorderBrush="#e2e8f0" BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#2563eb" CornerRadius="8,0,0,8"/>
<StackPanel Grid.Column="1" Padding="14,12" Spacing="4">
<TextBlock Text="ℹ️ Інформаційне повідомлення" FontWeight="SemiBold" Foreground="#1e40af"/>
<TextBlock Text="Border з CornerRadius='8,0,0,8' лівої частини для акцентної лінії."
FontSize="12" Foreground="#3b82f6" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</Border>
<!-- Badge-набір -->
<StackPanel Orientation="Horizontal" Spacing="8">
<Border Background="#dbeafe" CornerRadius="100" Padding="12,4">
<TextBlock Text="WPF" Foreground="#1e40af" FontSize="12" FontWeight="SemiBold"/>
</Border>
<Border Background="#dcfce7" CornerRadius="100" Padding="12,4">
<TextBlock Text="Avalonia" Foreground="#166534" FontSize="12" FontWeight="SemiBold"/>
</Border>
<Border Background="#fae8ff" CornerRadius="100" Padding="12,4">
<TextBlock Text="XAML" Foreground="#6b21a8" FontSize="12" FontWeight="SemiBold"/>
</Border>
<Border Background="#fef9c3" CornerRadius="100" Padding="12,4">
<TextBlock Text="C# 12" Foreground="#713f12" FontSize="12" FontWeight="SemiBold"/>
</Border>
</StackPanel>
</StackPanel>
GridSplitter — елемент, що дозволяє користувачеві перетягуванням змінювати розміри рядків і колонок у Grid. Це ключовий елемент для IDE-подібних інтерфейсів з регульованими панелями.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" MinWidth="100" MaxWidth="400"/>
<ColumnDefinition Width="4"/> <!-- Колонка для GridSplitter -->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Ліва панель -->
<TreeView Grid.Column="0"/>
<!-- GridSplitter: займає свою колонку цілком -->
<GridSplitter Grid.Column="1"
Width="4"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#e2e8f0"/>
<!-- Права панель -->
<TextBox Grid.Column="2" AcceptsReturn="True"/>
</Grid>
<!-- Вертикальний роздільник (між колонками): -->
<GridSplitter Grid.Column="1"
Width="4"
HorizontalAlignment="Stretch" <!-- займає всю ширину колонки -->
ResizeDirection="Columns"/>
<!-- Горизонтальний роздільник (між рядками): -->
<GridSplitter Grid.Row="1"
Height="4"
VerticalAlignment="Stretch" <!-- займає всю висоту рядка -->
HorizontalAlignment="Stretch" <!-- займає всю ширину -->
ResizeDirection="Rows"/>
ResizeBehaviorВизначає які сусідні рядки/колонки змінюються при перетягуванні:
PreviousAndNext (за замовчуванням): змінює попередню та наступнуPreviousAndCurrent: змінює попередню та поточнуCurrentAndNext: змінює поточну та наступнуBasedOnAlignment: автоматично визначається по HorizontalAlignmentLoading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Grid Height="360" Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" MinWidth="80"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="200" MinWidth="120"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*" MinWidth="100"/>
</Grid.ColumnDefinitions>
<!-- Ліва панель: Папки -->
<Border Grid.Column="0" Background="#1e293b">
<StackPanel Spacing="2" Margin="8">
<TextBlock Text="📬 ПОШТА" Foreground="#64748b" FontSize="10" FontWeight="Bold" Margin="8,12,0,8"/>
<Border Background="#2563eb" CornerRadius="6" Padding="10,6">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="📥" Foreground="White"/>
<TextBlock Text="Вхідні" Foreground="White" FontWeight="SemiBold"/>
<Border Background="#ef4444" CornerRadius="10" Padding="5,1" HorizontalAlignment="Right">
<TextBlock Text="12" Foreground="White" FontSize="10"/>
</Border>
</StackPanel>
</Border>
<Border Padding="10,6" CornerRadius="6">
<TextBlock Text="📤 Надіслані" Foreground="#94a3b8"/>
</Border>
<Border Padding="10,6" CornerRadius="6">
<TextBlock Text="⭐ Важливі" Foreground="#94a3b8"/>
</Border>
<Border Padding="10,6" CornerRadius="6">
<TextBlock Text="📋 Чернетки" Foreground="#94a3b8"/>
</Border>
<Border Padding="10,6" CornerRadius="6">
<TextBlock Text="🗑️ Кошик" Foreground="#94a3b8"/>
</Border>
</StackPanel>
</Border>
<!-- GridSplitter 1 -->
<GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Stretch"
Background="#334155" Cursor="SizeWE"/>
<!-- Середня панель: Список листів -->
<Border Grid.Column="2" Background="#f8fafc">
<ScrollViewer>
<StackPanel Spacing="0">
<Border Padding="12,10" Background="#eff6ff" BorderBrush="#e2e8f0" BorderThickness="0,0,0,1">
<StackPanel Spacing="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Андрій Коваль" FontWeight="Bold" Foreground="#1e293b" FontSize="12"/>
<TextBlock Text=" • 10:24" Foreground="#94a3b8" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Звіт за Q1 2025" FontSize="12" Foreground="#374151" FontWeight="SemiBold"/>
<TextBlock Text="Привіт! Надсилаю звіт за перший квартал..." FontSize="11" Foreground="#64748b" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Border>
<Border Padding="12,10" BorderBrush="#e2e8f0" BorderThickness="0,0,0,1">
<StackPanel Spacing="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="GitHub" Foreground="#374151" FontSize="12"/>
<TextBlock Text=" • вчора" Foreground="#94a3b8" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="[PR] Add GridSplitter support" FontSize="12" Foreground="#374151"/>
<TextBlock Text="A pull request was opened by..." FontSize="11" Foreground="#64748b" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Border>
<Border Padding="12,10" BorderBrush="#e2e8f0" BorderThickness="0,0,0,1">
<StackPanel Spacing="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Команда Avalonia" Foreground="#374151" FontSize="12"/>
<TextBlock Text=" • пн" Foreground="#94a3b8" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Release Notes 11.2.0" FontSize="12" Foreground="#374151"/>
<TextBlock Text="Нова версія вийшла з підтримкою..." FontSize="11" Foreground="#64748b" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Border>
<!-- GridSplitter 2 -->
<GridSplitter Grid.Column="3" Width="4" HorizontalAlignment="Stretch"
Background="#e2e8f0" Cursor="SizeWE"/>
<!-- Права панель: Вміст листа -->
<Border Grid.Column="4" Background="White">
<StackPanel Margin="16" Spacing="8">
<TextBlock Text="Звіт за Q1 2025" FontSize="16" FontWeight="Bold" Foreground="#1e293b"/>
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="Від:" Foreground="#94a3b8" FontSize="12"/>
<TextBlock Text="Андрій Коваль <a.koval@company.ua>" Foreground="#374151" FontSize="12"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="Кому:" Foreground="#94a3b8" FontSize="12"/>
<TextBlock Text="ivan@example.com" Foreground="#374151" FontSize="12"/>
</StackPanel>
<Separator/>
<TextBlock Text="Привіт Іване!" Foreground="#374151" FontSize="13"/>
<TextBlock Text="Надсилаю підготовлений звіт за перший квартал 2025 року. Загальний дохід зріс на 23% у порівнянні з Q1 2024." Foreground="#374151" FontSize="13" TextWrapping="Wrap"/>
<TextBlock Text="Звіт складається з наступних розділів: доходи, витрати, прогноз на Q2." Foreground="#374151" FontSize="13" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</Grid>
Реальні інтерфейси завжди є комбінацією панелей. Ключове правило:
Grid — основний каркас, StackPanel/WrapPanel — для простих списків всередині комірок.
<!-- Типова архітектура: DockPanel → Grid → StackPanel -->
<DockPanel>
<!-- Зовнішній рівень: DockPanel для Shell Layout -->
<Menu DockPanel.Dock="Top"/>
<StatusBar DockPanel.Dock="Bottom"/>
<!-- Середній рівень: Grid для основного layout -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Ліва панель: StackPanel для навігації -->
<ScrollViewer Grid.Column="0">
<StackPanel Spacing="4" Margin="8">
<Button Content="Пункт 1"/>
<Button Content="Пункт 2"/>
<!-- ... -->
</StackPanel>
</ScrollViewer>
<GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Stretch"/>
<!-- Права панель: Grid для форми -->
<ScrollViewer Grid.Column="2">
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<!-- ... -->
</Grid.RowDefinitions>
<!-- Поля форми -->
</Grid>
</ScrollViewer>
</Grid>
</DockPanel>
| Інструмент | Призначення |
|---|---|
Margin | Зовнішні відступи від сусідів/контейнера |
Padding | Внутрішні відступи між кордоном і вмістом |
HorizontalAlignment | Позиція у батьківській комірці (Left/Center/Right/Stretch) |
HorizontalContentAlignment | Позиція вмісту всередині контролу |
MinWidth/MaxWidth | Обмеження розмірів (адаптивність) |
ScrollViewer | Прокрутка — дати Grid/фіксовану висоту, не StackPanel |
ViewBox | Масштабування вмісту (Uniform/Fill/UniformToFill/None) |
Border | Рамка + фон + CornerRadius + Padding |
GridSplitter | Інтерактивна зміна розмірів зон Grid мишею |
Завдання: Побудуйте форму профілю користувача з коректними відступами і оформленням.
Вимоги:
Border (картка): Background White, CornerRadius=12, BorderBrush=#e2e8f0, Padding=24Grid (2 колонки: Auto для міток + * для полів)Margin="0,0,12,0" (відступ від поля)Margin="0,0,0,8" (нижній відступ між рядками) + Padding="10,7"MinWidth="100" у Footer Border з Background="#f8fafc" і Padding="16"Завдання на Badge: Додайте у куток картки Badge "✅ Підтверджено" (Border CornerRadius=100, Background="#dcfce7", Pill-форма).
Перевірка: Всі мітки вирівняні по правому краю відносно полів. Відступи рівномірні.
Завдання: Реалізуйте layout email-клієнта на основі наданого у статті прикладу, але з доповненнями.
Вимоги:
DockPanel: Toolbar зверху (кнопки "✉️ Написати", "🔄 Оновити"), StatusBar знизуGrid з 5 колонками: Sidebar(140px) + Splitter(4px) + ListPanel(180px) + Splitter(4px) + Content(*)GridSplitter на кожному роздільнику з Cursor="SizeWE" і MinWidth/MaxWidth на крайніх колонкахScrollViewer → StackPanel з 5+ папокScrollViewer → список з 8+ "листів" (Border + StackPanel для кожного)Grid з 2 рядками: заголовок (60px) + ScrollViewer (*)Перевірка: Перетягування кожного GridSplitter змінює ширину сусідніх панелей. Sidebar і ListPanel не звужуються нижче MinWidth.
Завдання: Сторінка налаштувань з групами секцій, прокруткою та валідацією.
Layout: DockPanel → Header (60px, DockPanel.Dock=Top) + ScrollViewer (Fill)
Всередині ScrollViewer: StackPanel Spacing="16" Margin="24" з 4+ секціями.
Кожна секція: Border CornerRadius="10" з внутрішнім StackPanel:
Auto + *): мітка + контрол (TextBox/ComboBox/Slider/CheckBox)Секції:
Background="#fff1f2" BorderBrush="#fecdd3" — кнопки "Видалити акаунт"Перевірка: ScrollViewer прокручується. Секції вирівняні. Slider FontSize оновлює TextBlock.FontSize через Binding ElementName.
Grid, Canvas, UniformGrid
Вивчаємо Grid — найпотужнішу панель WPF: типи розмірів Auto/**/fixed, Grid.Row/Column, RowSpan/ColumnSpan, SharedSizeGroup. Розбираємо Canvas та UniformGrid.
Адаптивний Layout та найкращі практики
Responsive Layout у WPF: Star sizing, Visibility (Collapsed/Hidden), SizeChanged event, MinWidth як responsive tool, WrapPanel для адаптивних сіток, best practices.