Тема 2.1: Макети (Layouts) у WinUI 3
Вступ
Вітаємо! Ми вже вміємо створювати прості елементи UI за допомогою XAML, але як розмістити їх у вікні так, щоб усе виглядало красиво і зручно? Для цього в WinUI 3 є макети (layouts) — спеціальні контейнери, які допомагають організувати controls (кнопки, текстові поля тощо). Сьогодні ми розберемо всі основні макети, їхні властивості та створимо адаптивну форму. Готові до дизайну? Тоді почнімо!
Компонування та елементи UI в WinUI 3
Компонування
При розробці користувацького інтерфейсу (UI) у WinUI 3 значна частина зусиль спрямовується на створення привабливого та зручного дизайну. Однак не менш важливим є забезпечення гнучкості інтерфейсу — його здатності адаптуватися до змін розміру вікна, вмісту чи навіть локалізації. Наприклад, при зміні розміру вікна елементи UI повинні коректно масштабуватися, зберігаючи зручність використання.
Ще одна поширена проблема — зміна вмісту елементів через локалізацію. Рядки різної довжини в різних мовах можуть призводити до обрізання тексту або неефективного використання простору, якщо UI спроєктовано з фіксованими розмірами. Усе це пов’язано з компонуванням — процесом визначення розмірів і розташування елементів.
У старих технологіях (наприклад, Windows Forms) компонування було обмеженим: розробники задавали фіксовані координати та розміри, а для адаптивності писали складний код вручну. WinUI 3, як і його попередник WPF, вирішує ці проблеми за допомогою панелей — спеціальних контейнерів із вбудованою логікою компонування. У WinUI 3 ця концепція адаптована до Windows App SDK, зберігаючи гнучкість і сучасний підхід.
Основні принципи компонування в WinUI 3
- Розмір за вмістом: Елементам не задають фіксовані розміри — вони адаптуються до вмісту та логіки панелі. Можна використовувати
MinWidth,MaxHeightтощо для обмежень. - Відносне позиціонування: Координати не фіксуються, а визначаються панеллю та відступами (
Margin). - Винятки: Фіксовані розміри чи позиції допустимі, але їх варто уникати, якщо це можливо, щоб дотримуватися філософії адаптивного дизайну.
Відмінність від WPF: У WPF панелі були частиною .NET Framework і простору імен System.Windows.Controls. У WinUI 3 вони належать до Microsoft.UI.Xaml.Controls, але принципи залишилися схожими.
1. Етапи компонування
Компонування в WinUI 3 відбувається в два етапи: вимірювання (Measure) і розташування (Arrange). Цей процес запускається при першому відображенні UI або при змінах (наприклад, зміна розміру вікна чи вмісту).
- Етап вимірювання:
- Обхід візуального дерева через метод
Measure. - Кожен елемент повідомляє свій бажаний розмір на основі вмісту та доступного простору.
- Доступний простір передається як параметр (наприклад, ширина 200, висота
Double.PositiveInfinityдля необмеженого вертикального простору). - Типи компонування:
- Обмежене: Відомий доступний простір (наприклад, у
Grid). - Необмежене: Простір не обмежений (наприклад, у прокручуваній області).
- Обмежене: Відомий доступний простір (наприклад, у
- Обхід візуального дерева через метод
- Етап розташування:
- Метод
Arrangeрозставляє елементи, використовуючи розміри з етапу вимірювання. - Якщо бажаний розмір недоступний, елементи можуть обрізатися або масштабуватися (наприклад, зображення стискається).
- Метод
Приклад: Текстовий блок із увімкненим перенесенням слів (TextWrapping="Wrap") зменшує ширину, але збільшує висоту, якщо простір обмежений горизонтально.
Відмінність від WPF: Логіка ідентична, але в WinUI 3 методи належать до Microsoft.UI.Xaml.UIElement.
Апаратно-незалежні одиниці
У WinUI 3 розміри задаються в апаратно-незалежних одиницях (1/96 дюйма), а не в пікселях. Це забезпечує однаковий вигляд UI на екранах із різною щільністю пікселів (DPI). Наприклад, Width="96" завжди дорівнює 1 дюйму, незалежно від роздільної здатності.
Відмінність від WPF: Поведінка та одиниці ідентичні.
11. Панелі (Layouts) у WinUI 3
Панелі — це основа компонування в WinUI 3. Усі вони успадковуються від базового класу Microsoft.UI.Xaml.Controls.Panel і мають унікальну логіку розміщення дочірніх елементів. Ось огляд основних панелей "зверху" (тобто тих, що використовуються як головні контейнери).
Властивості класу Panel
Background: Пензель для заливки фону (наприклад,SolidColorBrush).Children: Колекція дочірніх елементів (UIElementCollection).IsItemsHost: Вказує, чи є панель контейнером для елементів ізItemsControl.- Приєднана властивість
ZIndex: Визначає порядок накладання (вищі значення — ближче до переднього плану).
Основні панелі для компонування
Grid
- Опис: Сітка з рядками та стовпцями для точного позиціонування.
- Логіка: Елементи розміщуються в клітинках, визначених через
RowDefinitionsіColumnDefinitions. - Приклад: Форма введення з вирівняними полями.
<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="Ім’я:" Grid.Row="0" Grid.Column="0" Margin="5"/> <TextBox Grid.Row="0" Grid.Column="1" Margin="5"/> <TextBlock Text="Вік:" Grid.Row="1" Grid.Column="0" Margin="5"/> <TextBox Grid.Row="1" Grid.Column="1" Margin="5"/> </Grid> - Особливості: Підтримує
Auto(розмір за вмістом) і*(пропорційний розподіл простору).
<Grid x:Name="LayoutRoot" Background="#555555"
Width="400" Height="300"
ColumnDefinitions="250, 150"
RowDefinitions="Auto, 2*, *">
<TextBlock Grid.Row="0" Grid.Column="0"
Grid.ColumnSpan="2"
Margin="10" FontWeight="Bold"
Text="Contoso Corporation"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Grid x:Name="FormLayoutGrid" Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="First Name" Margin="10"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Margin="10" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name" Margin="10"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Margin="10" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Address" Margin="10"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox Grid.Row="2" Grid.Column="1" Margin="10" />
</Grid>
</Grid>
public MainPage()
{
this.InitializeComponent();
LayoutDesign();
}
private void LayoutDesign()
{
//Create Stackpanel for ListBox Control and its description
StackPanel DeptStackPanel = new StackPanel();
DeptStackPanel.Margin = new Thickness(10);
LayoutRoot.Children.Add(DeptStackPanel);
Grid.SetColumn(DeptStackPanel, 1);
Grid.SetRow(DeptStackPanel, 1);
TextBlock DeptListHeading = new TextBlock();
DeptListHeading.Text = "Department";
ListBox DeptList = new ListBox();
DeptList.Items.Add("Finance");
DeptList.Items.Add("Marketing");
DeptList.Items.Add("Human Resources");
DeptList.Items.Add("Payroll");
DeptStackPanel.Children.Add(DeptListHeading);
DeptStackPanel.Children.Add(DeptList);
//Create StackPanel for buttons
StackPanel ButtonsStackPanel = new StackPanel();
ButtonsStackPanel.Margin = new Thickness(10);
ButtonsStackPanel.Orientation = Orientation.Horizontal;
ButtonsStackPanel.HorizontalAlignment = HorizontalAlignment.Center;
LayoutRoot.Children.Add(ButtonsStackPanel);
Grid.SetColumn(ButtonsStackPanel, 0);
Grid.SetRow(ButtonsStackPanel, 2);
Grid.SetColumnSpan(ButtonsStackPanel, 2);
Button BackButton = new Button();
BackButton.Content = "Back";
BackButton.Width = 100;
Button CancelButton = new Button();
CancelButton.Content = "Cancel";
CancelButton.Width = 100;
Button NextButton = new Button();
NextButton.Content = "Next";
NextButton.Width = 100;
ButtonsStackPanel.Children.Add(BackButton);
ButtonsStackPanel.Children.Add(CancelButton);
ButtonsStackPanel.Children.Add(NextButton);
BackButton.Margin = new Thickness(10);
CancelButton.Margin = new Thickness(10);
NextButton.Margin = new Thickness(10);
}
}

Grid у WinUI 3
Grid — це панель компонування, яка розміщує дочірні елементи в рядках і стовпцях.
Визначення структури
Для налаштування Grid у XAML використовуються:
Grid.RowDefinitions— визначає рядки черезRowDefinition.Grid.ColumnDefinitions— визначає стовпці черезColumnDefinition.
Розташування елементів задається приєднаними властивостями Grid.Row і Grid.Column.
Налаштування розмірів
RowDefinition.Height— висота рядка.ColumnDefinition.Width— ширина стовпця. Типи розмірів:- Фіксований: Наприклад,
"50". Auto: Розмір за вмістом.*(Star): Пропорційний розподіл (наприклад,"1*"або"2*").
За замовчуванням кожен рядок і стовпець ділять простір порівну. Без визначення — один рядок і один стовпець.
Спрощений синтаксис
Для простих сіток:
<Grid ColumnDefinitions="1*, 2*, Auto, 50" RowDefinitions="1*, Auto, 50, 30, 10">
<!-- Вміст -->
</Grid>
Повний синтаксис
Для детального налаштування (наприклад, з MaxHeight або прив’язкою):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="{x:Bind RowHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Вміст -->
</Grid>
Об’єднання клітинок
Grid.RowSpan— кількість рядків, які охоплює елемент.Grid.ColumnSpan— кількість стовпців, які охоплює елемент.
Вирівнювання та відступи
Margin— відстань між елементом і межами клітинки.HorizontalAlignment/VerticalAlignment— позиціонування в клітинці (Left,Center,Right,Top,Bottom,Stretch).
Приклад із об’єднанням і впливом на розміри
<Grid Background="Yellow" Width="300" ColumnDefinitions="50, *" RowDefinitions="Auto, 0">
<Ellipse Grid.Row="0" Grid.Column="0" Height="50" Fill="Red" Grid.RowSpan="2"/>
<Rectangle Grid.Row="0" Grid.Column="1" Fill="Green" Height="100"/>
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Blue" Height="100"/>
</Grid>
Тут червона еліпса впливає на висоту другого рядка (MinHeight=50), хоча його висота задана як 0.
Властивості рамки
Grid підтримує вбудовану рамку:
BorderBrush— колір рамки.BorderThickness— товщина рамки.CornerRadius— заокруглення кутів.Padding— внутрішні відступи. Приклад:
<Grid BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
<TextBlock Text="Привіт, світ!"/>
</Grid>
Приєднані властивості
Grid підтримує приєднані властивості для дочірніх елементів:
Grid.Column:- Тип:
int. - Ідентифікатор:
ColumnProperty. - Методи:
GetColumn,SetColumn. - Значення: Індекс стовпця (від 0, негативні не дозволені).
- Тип:
Grid.ColumnSpan:- Тип:
int. - Ідентифікатор:
ColumnSpanProperty. - Методи:
GetColumnSpan,SetColumnSpan. - Значення: Кількість стовпців (0 і негативні не дозволені, більше максимуму = усі стовпці).
- Тип:
Grid.Row:- Тип:
int. - Ідентифікатор:
RowProperty. - Методи:
GetRow,SetRow. - Значення: Індекс рядка (від 0).
- Тип:
Grid.RowSpan:- Тип:
int. - Ідентифікатор:
RowSpanProperty. - Методи:
GetRowSpan,SetRowSpan. - Значення: Кількість рядків (0 і негативні не дозволені).
- Тип:
Альтернатива
Для складнішого компонування з обгортанням використовуйте VariableSizedWrapGrid, який краще обробляє широкий вміст.
StackPanel
- Опис: Розташовує елементи в одному напрямку (вертикально чи горизонтально).
- Логіка: Елементи "складаються" один за одним.
- Приклад: Список кнопок.
<StackPanel Orientation="Vertical" Spacing="10"> <Button Content="Нова гра"/> <Button Content="Налаштування"/> <Button Content="Вихід"/> </StackPanel> - Особливості:
Spacingзадає відстань між елементами (нова функція в WinUI).
У наступному прикладі показано, як створити StackPanel з елементів.
<StackPanel Margin="20">
<Rectangle Fill="Red" Width="50" Height="50" Margin="5" />
<Rectangle Fill="Blue" Width="50" Height="50" Margin="5" />
<Rectangle Fill="Green" Width="50" Height="50" Margin="5" />
<Rectangle Fill="Purple" Width="50" Height="50" Margin="5" />
</StackPanel>
<Grid x:Name="LayoutRoot" Width="500" Height="500">
<StackPanel x:Name="MyStackPanel">
<TextBlock x:Name="TB1" Text="First Name" Width="77" HorizontalAlignment="Left"/>
<TextBlock x:Name="TB2" Text="Last Name" Width="78" HorizontalAlignment="Left"/>
<TextBlock x:Name="TB3" Text="Address" Width="60" HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
private void Rearrange()
{
TextBlock TB4 = new TextBlock();
TB4.Text = "Age";
MyStackPanel.Children.Insert(2, TB4);
}

За замовчуванням StackPanel стекує елементи вертикально зверху донизу в порядку їх оголошення. Для властивості Orientation можна задати значення Горизонтальна , щоб елементи стека зліва направо.
Ви можете вставляти елементи в StackPanel у певному розташуванні за допомогою методу InsertAt у коді програмної частини.
Властивості кордону
StackPanel визначає властивості кордону, які дають змогу малювати кордон навколо StackPanel без використання додаткового елемента Border . Ці властивості: StackPanel.BorderBrush, StackPanel.BorderThickness, StackPanel.CornerRadius і StackPanel.Padding.
<StackPanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
<TextBlock Text="Hello World!"/>
</StackPanel>
Canvas
- Опис: Абсолютне позиціонування з фіксованими координатами.
- Логіка: Елементи розміщуються за
Canvas.LeftіCanvas.Top. - Приклад: Графічний редактор.
<Canvas> <Ellipse Width="50" Height="50" Fill="Red" Canvas.Left="20" Canvas.Top="30"/> <Rectangle Width="70" Height="40" Fill="Blue" Canvas.Left="80" Canvas.Top="60"/> </Canvas> - Особливості: Не адаптується до змін розміру — використовуйте обережно.

Canvas — це панель компонування, яка підтримує абсолютне позиціонування дочірніх елементів відносно верхнього лівого кута.
Особливості
- Використовує координати
xіy(у пікселях) для розміщення елементів. - Координати задаються через приєднані властивості
Canvas.Left(відстань від лівого краю) іCanvas.Top(відстань від верхнього краю). - Не адаптується до розміру вікна, тому
GridабоStackPanelчасто кращі.
Вкладеність
Canvasможна вкладати, координати дочірніх елементів відносні до найближчого батьківськогоCanvas.
Дочірні елементи
- Мають бути типу
UIElement. - У XAML додаються як вміст
Canvas. - У коді — через властивість
Children.
Видимість
Canvas і його дочірні елементи невидимі, якщо:
Visibility="Collapsed".Opacity="0".Background="null".HeightабоWidthдорівнює 0.- Якщо немає дочірніх елементів і
Height/Width—Auto, розміри відсутні.
Приєднані властивості
Canvas.Left:- Тип:
Double. - Ідентифікатор:
LeftProperty. - Методи:
GetLeft,SetLeft. - Опис: Горизонтальний відступ від лівого краю батьківського
Canvas. Зазвичай позитивне ціле число, дробові значення можливі, але можуть викликати проблеми з рендерингом (див.UseLayoutRounding).
- Тип:
Canvas.Top:- Тип:
Double. - Ідентифікатор:
TopProperty. - Методи:
GetTop,SetTop. - Опис: Вертикальний відступ від верхнього краю батьківського
Canvas. Аналогічно доLeft.
- Тип:
Canvas.ZIndex:- Тип:
Int32. - Ідентифікатор:
ZIndexProperty. - Методи:
GetZIndex,SetZIndex. - Опис: Визначає порядок накладання. Вищі значення — вище в порядку малювання. За замовчуванням 0. При однакових значеннях перевага за останнім елементом у XAML або
Children. Негативні значення (наприклад,-99) дозволені.
- Тип:
Приклад
<Canvas Background="LightBlue">
<Ellipse Width="50" Height="50" Fill="Red" Canvas.Left="50" Canvas.Top="50"/>
<Rectangle Width="70" Height="40" Fill="Green" Canvas.Left="120" Canvas.Top="80" Canvas.ZIndex="1"/>
</Canvas>
RelativePanel
- Опис: Відносне позиціонування елементів один до одного.
- Логіка: Використовує приєднані властивості (наприклад,
RelativePanel.RightOf). - Приклад: Адаптивний UI.
<RelativePanel> <Button x:Name="startButton" Content="Старт"/> <TextBlock Text="Натисни Старт" RelativePanel.RightOf="startButton" Margin="10,0,0,0"/> </RelativePanel> - Особливості: Гнучкий для динамічних макетів.

Ось детальний і скорочений опис RelativePanel у WinUI 3 українською мовою:
RelativePanel у WinUI 3
RelativePanel — це панель компонування для UI без чіткого лінійного порядку (на відміну від StackPanel чи Grid). Підходить для складних макетів із вкладеними панелями.
Особливості
- Розташування елементів визначається відносно інших елементів або панелі за допомогою приєднаних властивостей.
- Ідеально для адаптивного UI разом із
AdaptiveTrigger.
Приклад
<RelativePanel BorderBrush="Gray" BorderThickness="10">
<Rectangle x:Name="RedRect" Fill="Red" MinHeight="100" MinWidth="100"/>
<Rectangle x:Name="BlueRect" Fill="Blue" MinHeight="100" MinWidth="100" RelativePanel.RightOf="RedRect"/>
<Rectangle x:Name="GreenRect" Fill="Green" MinHeight="100" Margin="0,5,0,0"
RelativePanel.Below="RedRect" RelativePanel.AlignLeftWith="RedRect" RelativePanel.AlignRightWith="BlueRect"/>
<Rectangle Fill="Yellow" MinHeight="100"
RelativePanel.Below="GreenRect" RelativePanel.AlignLeftWith="BlueRect" RelativePanel.AlignRightWithPanel="True"/>
</RelativePanel>
Позиція за замовчуванням
- Необмежений елемент займає весь простір панелі та розміщується в координатах (0,0). Якщо другий елемент позиціонується відносно такого, він може вийти за межі панелі. Приклад:
<RelativePanel>
<Rectangle x:Name="RectA" Fill="Red" Height="40" Width="40"/>
<Rectangle x:Name="RectB" Fill="Blue" Height="40" Width="40" RelativePanel.Above="RectA"/>
</RelativePanel>
Тут RectB не видно, бо виштовхується за межі.
Кругові залежності
- Виникають, коли два елементи посилаються один на одного (наприклад,
AboveіBelow). Це викликає помилку компіляції. Приклад:
<RelativePanel>
<Rectangle x:Name="RectA" Fill="Red" Height="40" Width="40" RelativePanel.Above="RectB"/>
<Rectangle x:Name="RectB" Fill="Blue" Height="40" Width="40" RelativePanel.Below="RectA"/>
</RelativePanel>
Конфлікти відносин
- При кількох відносинах для однієї межі пріоритет такий:
- Вирівнювання з панеллю (
AlignTopWithPanel,AlignLeftWithPanelтощо). - Вирівнювання з елементом (
AlignTopWith,AlignLeftWithтощо). - Позиційні відносини (
Above,Below,RightOf,LeftOf).
- Вирівнювання з панеллю (
- Вирівнювання по центру (
AlignVerticalCenterWith,AlignHorizontalCenterWithPanel) застосовується окремо, якщо немає конфліктів. HorizontalAlignmentіVerticalAlignmentобробляються після відносин.
Властивості рамки
BorderBrush— колір рамки.BorderThickness— товщина рамки.CornerRadius— заокруглення кутів.Padding— внутрішні відступи. Приклад:
<RelativePanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
<TextBox x:Name="textBox1" RelativePanel.AlignLeftWithPanel="True"/>
<Button Content="Надіслати" RelativePanel.Below="textBox1"/>
</RelativePanel>
Приєднані властивості
Above:- Тип:
object. - Ідентифікатор:
AboveProperty. - Методи:
GetAbove,SetAbove. - Опис: Елемент розміщується над вказаним.
- Тип:
AlignBottomWith:- Тип:
object. - Ідентифікатор:
AlignBottomWithProperty. - Методи:
GetAlignBottomWith,SetAlignBottomWith. - Опис: Нижня межа вирівнюється з нижньою межею іншого елемента.
- Тип:
AlignBottomWithPanel:- Тип:
Boolean. - Ідентифікатор:
AlignBottomWithPanelProperty. - Методи:
GetAlignBottomWithPanel,SetAlignBottomWithPanel. - Опис: Нижня межа прилягає до нижньої межі панелі.
- Тип:
AlignHorizontalCenterWith:- Тип:
object. - Ідентифікатор:
AlignHorizontalCenterWithProperty. - Методи:
GetAlignHorizontalCenterWith,SetAlignHorizontalCenterWith. - Опис: Горизонтальний центр вирівнюється з центром іншого елемента.
- Тип:
AlignHorizontalCenterWithPanel:- Тип:
Boolean. - Ідентифікатор:
AlignHorizontalCenterWithPanelProperty. - Методи:
GetAlignHorizontalCenterWithPanel,SetAlignHorizontalCenterWithPanel. - Опис: Горизонтальний центр прилягає до осі панелі.
- Тип:
AlignLeftWith:- Тип:
object. - Ідентифікатор:
AlignLeftWithProperty. - Методи:
GetAlignLeftWith,SetAlignLeftWith. - Опис: Ліва межа вирівнюється з лівою межею іншого елемента.
- Тип:
AlignLeftWithPanel:- Тип:
Boolean. - Ідентифікатор:
AlignLeftWithPanelProperty. - Методи:
GetAlignLeftWithPanel,SetAlignLeftWithPanel. - Опис: Ліва межа прилягає до лівої межі панелі.
- Тип:
AlignRightWith:- Тип:
object. - Ідентифікатор:
AlignRightWithProperty. - Методи:
GetAlignRightWith,SetAlignRightWith. - Опис: Права межа вирівнюється з право
- Тип:
VariableSizedWrapGrid
- Опис: Сітка з обгортанням, де елементи можуть мати різні розміри.
- Логіка: Елементи заповнюють рядки чи стовпці, переносяться при нестачі місця.
- Приклад: Галерея зображень.
<VariableSizedWrapGrid MaximumRowsOrColumns="3" ItemWidth="100" ItemHeight="100"> <Rectangle Fill="Red" Width="100" Height="100"/> <Rectangle Fill="Green" Width="200" Height="100" VariableSizedWrapGrid.ColumnSpan="2"/> <Rectangle Fill="Blue" Width="100" Height="200" VariableSizedWrapGrid.RowSpan="2"/> </VariableSizedWrapGrid> - Особливості: Підтримує
RowSpanіColumnSpan.

Ось детальний опис VariableSizedWrapGrid у WinUI 3 українською мовою з порівнянням із Grid:
VariableSizedWrapGrid — це панель компонування, яка розміщує дочірні елементи в рядках і стовпцях із можливістю обгортання та об’єднання клітинок.
Особливості
- Елементи розташовуються в рядках або стовпцях і переносяться на новий рядок/стовпець після досягнення
MaximumRowsOrColumns. - Властивість
Orientationвизначає напрямок:Vertical: Заповнення по стовпцях зверху вниз, обгортання зліва направо:1 4 7 2 5 8 3 6 9Horizontal: Заповнення по рядках зліва направо, обгортання зверху вниз:1 2 3 4 5 6 7 8 9
- Базові розміри клітинок задаються через
ItemWidthіItemHeight.
Об’єднання клітинок
VariableSizedWrapGrid.RowSpan— кількість рядків, які охоплює елемент.VariableSizedWrapGrid.ColumnSpan— кількість стовпців, які охоплює елемент.- Корисно для великих елементів, щоб уникнути порожнього простору.
Приклад
<VariableSizedWrapGrid MaximumRowsOrColumns="3" ItemWidth="100" ItemHeight="100" Orientation="Horizontal">
<Rectangle Fill="Red" Width="100" Height="100"/>
<Image x:Name="MyBigImage" Source="image.jpg"
VariableSizedWrapGrid.ColumnSpan="2" VariableSizedWrapGrid.RowSpan="2"/>
<Rectangle Fill="Blue" Width="100" Height="100"/>
</VariableSizedWrapGrid>
Приєднані властивості
ColumnSpan:- Тип:
int. - Ідентифікатор:
ColumnSpanProperty. - Методи:
GetColumnSpan,SetColumnSpan. - Опис: Кількість стовпців, які охоплює елемент. Значення 0 або негативні заборонені. Якщо більше максимуму — охоплює всі стовпці.
- Тип:
RowSpan:- Тип:
int. - Ідентифікатор:
RowSpanProperty. - Методи:
GetRowSpan,SetRowSpan. - Опис: Кількість рядків, які охоплює елемент. Аналогічно до
ColumnSpan.
- Тип:
Порівняння з Grid
| Аспект | Grid | VariableSizedWrapGrid |
|---|---|---|
| Структура | Сітка з фіксованою кількістю рядків і стовпців, визначених через RowDefinitions і ColumnDefinitions. | Сітка з обгортанням, де рядки/стовпці створюються автоматично до MaximumRowsOrColumns. |
| Позиціонування | Точне, через Grid.Row і Grid.Column. | Автоматичне заповнення з обгортанням за Orientation. |
| Об’єднання клітинок | Підтримує RowSpan і ColumnSpan. | Підтримує RowSpan і ColumnSpan. |
| Розміри | Гнучкі (Auto, *, фіксовані значення). | Базові розміри через ItemWidth/ItemHeight, але елементи можуть бути більшими через Span. |
| Адаптивність | Не обгортає вміст, підходить для статичних макетів. | Обгортає вміст, підходить для динамічних макетів (наприклад, галереї). |
| Типове використання | Форми, таблиці, структуровані макети. | Плиткові макети, списки з різними розмірами елементів. |
| Продуктивність | Ефективний для фіксованих структур. | Може бути менш ефективним при великій кількості елементів через обгортання. |
Приклад Grid для порівняння
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="0"/>
<Image Source="image.jpg" Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"/>
</Grid>
Ключові відмінності
Gridвимагає явного визначення структури, тоді якVariableSizedWrapGridавтоматично обгортає елементи.Gridкращий для чітких, статичних макетів, аVariableSizedWrapGrid— для гнучких, плиткових інтерфейсів.
11.1. Детальний огляд елементів UI
Нижче наведено детальний опис кожного елемента з популярними властивостями та реалістичними прикладами для WinUI 3.
Border
- Опис: Контейнер із рамкою навколо одного дочірнього елемента.
- Популярні властивості:
BorderBrush: Пензель для рамки (наприклад,SolidColorBrush).BorderThickness: Товщина рамки (наприклад, "2" або "2,4,2,4" для різних сторін).CornerRadius: Радіус заокруглення кутів.Padding: Внутрішні відступи.Background: Фон усередині рамки.Child: Єдиний дочірній елемент.
- Приклад: Виділення текстового поля з тінню.
<Border BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Padding="10" Background="LightGray"> <TextBox Text="Введіть ім’я" PlaceholderText="Ім’я"/> </Border>

<Border BorderBrush="Gray" BorderThickness="4"
Height="108" Width="64">
<StackPanel>
<Rectangle Fill="Yellow"/>
<Rectangle Fill="Green"/>
</StackPanel>
</Border>
<Border Background="Coral" Width="300" Padding="10" CornerRadius="20">
<TextBlock FontSize="16">Text Surrounded by a Border</TextBlock>
</Border>
Expander
- Опис: Розгортаний контейнер із заголовком і вмістом.
- Популярні властивості:
Header: Заголовок (текст або елемент).Content: Вміст, що розгортається.IsExpanded: Стан розгортання (true/false).ExpandDirection: Напрямок розгортання (Down,Up,Left,Right).Padding: Внутрішні відступи вмісту.
- Приклад: Панель налаштувань.
<Expander Header="Налаштування звуку" ExpandDirection="Down" IsExpanded="False" Padding="10"> <StackPanel> <CheckBox Content="Увімкнути звук"/> <Slider Minimum="0" Maximum="100" Value="50" Width="200"/> </StackPanel> </Expander>

Expander — це елемент керування, який дозволяє приховувати менш важливий вміст, коли простір на екрані обмежений, залишаючи основний вміст завжди видимим.
Особливості
- Заголовок (
Header): Завжди видимий, містить основний вміст (текст або складний UI). - Вміст (
Content): Додатковий вміст, який можна розгорнути чи згорнути через взаємодію з заголовком. - При розгортанні вміст зміщує інші елементи UI (не накладається).
- Напрямок розгортання: вгору або вниз (властивість
ExpandDirection).
Приклад
<Expander Header="Налаштування" ExpandDirection="Down" IsExpanded="False">
<StackPanel>
<CheckBox Content="Увімкнути звук"/>
<Slider Minimum="0" Maximum="100" Value="50"/>
</StackPanel>
</Expander>
Налаштування стилю
- Стандартний стиль і шаблон визначені в
generic.xaml(розташування:\Users\<username>\.nuget\packages\microsoft.windowsappsdk\<version>\lib\uap10.0\Microsoft.UI\Themes\generic.xaml). - Можна змінити
StyleіControlTemplateдля унікального вигляду. - Легке стилювання (наприклад, зміна
Background) можливе через ресурси без зміни шаблону (див. статтю про XAML-стилі).
ItemsRepeater
- Опис: Легкий контейнер для повторення елементів без стилізації (на відміну від
ListView). - Популярні властивості:
ItemsSource: Джерело даних (колекція).ItemTemplate: Шаблон для кожного елемента.Layout: Логіка компонування (наприклад,StackLayout,UniformGridLayout).
- Приклад: Список завдань.
<ItemsRepeater x:Name="taskRepeater"> <ItemsRepeater.ItemTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" Margin="5"> <TextBlock Text="{Binding}" Padding="5"/> </Border> </DataTemplate> </ItemsRepeater.ItemTemplate> <ItemsRepeater.Layout> <StackLayout Orientation="Vertical"/> </ItemsRepeater.Layout> </ItemsRepeater>taskRepeater.ItemsSource = new string[] { "Купити молоко", "Зателефонувати", "Написати звіт" };
RadioButtons
- Опис: Група взаємовиключних опцій.
- Популярні властивості:
Header: Заголовок групи.Items: Список опцій (як дочірніRadioButton).SelectedIndex: Індекс вибраної опції.SelectedItem: Вибраний об’єкт.MaxColumns: Максимальна кількість стовпців для компонування.
- Приклад: Вибір рівня складності.
<RadioButtons Header="Рівень складності" SelectedIndex="1" MaxColumns="3"> <RadioButton Content="Легкий"/> <RadioButton Content="Середній"/> <RadioButton Content="Складний"/> </RadioButtons>
SplitView
- Опис: Панель із бічною навігацією (наприклад, hamburger-меню).
- Популярні властивості:
Pane: Вміст бічної панелі.Content: Основний вміст.PanePlacement: Розташування панелі (LeftабоRight).DisplayMode: Режим відображення (Overlay,Inline,CompactOverlay,CompactInline).IsPaneOpen: Стан панелі (true/false).PaneBackground: Фон бічної панелі.
- Приклад: Навігаційне меню.
<SplitView x:Name="splitView" PanePlacement="Left" DisplayMode="Overlay" IsPaneOpen="False"> <SplitView.Pane> <StackPanel Padding="10"> <Button Content="Головна" Margin="0,0,0,10"/> <Button Content="Налаштування"/> </StackPanel> </SplitView.Pane> <SplitView.Content> <TextBlock Text="Вітаємо на головній сторінці" Margin="20"/> </SplitView.Content> </SplitView>splitView.IsPaneOpen = true; // Відкрити панель програмно

Viewbox
- Опис: Масштабує вміст до доступного простору.
- Популярні властивості:
Child: Єдиний дочірній елемент.Stretch: Тип масштабування (None,Fill,Uniform,UniformToFill).StretchDirection: Напрямок масштабування (UpOnly,DownOnly,Both).MaxWidth/MaxHeight: Обмеження розміру.
- Приклад: Адаптивна іконка.
<Viewbox MaxWidth="150" MaxHeight="150" Stretch="Uniform"> <Ellipse Width="100" Height="100" Fill="Orange"/> </Viewbox>
Висновок
Панелі в WinUI 3 (Grid, StackPanel, тощо) забезпечують гнучке компонування, а елементи, як Border чи Expander, додають функціональність і стиль. Кожен елемент має набір властивостей, які дозволяють точно налаштувати його поведінку та вигляд. Використовуйте ці інструменти разом, щоб створювати сучасні, адаптивні інтерфейси!
6. Практика: Створення форми із сіткою
Створимо форму для введення даних із використанням Grid.
Завдання
- Поля: "Name" і "Age" (TextBox), кнопка "Submit".
Крок 1: Розмітка
У MainWindow.xaml замініть вміст <Window> на:
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Name:" Grid.Row="0" Grid.Column="0" Margin="0,0,10,10" />
<TextBox x:Name="NameInput" Grid.Row="0" Grid.Column="1" Margin="0,0,0,10" />
<TextBlock Text="Age:" Grid.Row="1" Grid.Column="0" Margin="0,0,10,10" />
<TextBox x:Name="AgeInput" Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" />
<Button Content="Submit" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" Click="Submit_Click" />
</Grid>
Крок 2: Логіка
У MainWindow.xaml.cs додайте:
private void Submit_Click(object sender, RoutedEventArgs e)
{
string name = NameInput.Text;
string age = AgeInput.Text;
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(age))
{
// Для демонстрації просто виведемо в дебаг
System.Diagnostics.Debug.WriteLine($"Name: {name}, Age: {age}");
}
}
Крок 3: Тестування
- Запустіть (F5).
- Введіть дані й натисніть "Submit".
- Змініть розмір вікна — поле вводу розтягнеться завдяки
Width="*"уColumnDefinition.
Питання для роздумів
- Який макет краще обрати для вертикального меню:
StackPanelчиGrid? - Як зробити так, щоб кнопка завжди була внизу вікна, незалежно від його розміру?
Ресурси
- Документація макетів: learn.microsoft.com/windows/apps/design/layout
- Контроли WinUI: learn.microsoft.com/windows/apps/winui/winui3/xaml-controls
Висновок
Ви освоїли всі основні макети WinUI 3: від простого StackPanel до гнучкого Grid і специфічного Canvas. Ми навчилися розміщувати елементи, працювати з сіткою та створювати адаптивний дизайн. Наступного разу ми додамо стилі, щоб наш UI став ще привабливішим. Чудова робота!
Створення простого додатка погоди за допомогою Grid і StackPanel
Крок 2. Визначення сітки
У XAML сітка складається з низки рядків і стовпців. Зазначивши рядок і стовпчик елемента в сітці, можна розмістити і помістити інші елементи в користувацький інтерфейс. Рядки і стовпці визначаються елементами RowDefinition і ColumnDefinition .
Щоб почати створення макета, відкрийте MainPage.xaml за допомогою Оглядача рішень і замініть автоматично створений елемент Grid цим кодом.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
Нова сітка створює набір двох рядків і стовпців, що визначають макет інтерфейсу програми. Перший стовпець має ширину "3*", а другий має значення "5*", розділивши горизонтальний простір між двома стовпчиками у співвідношенні від 3:5. Таким самим чином, два рядки мають висоту "2*" і "" відповідно, тому сітка виділяє вдвічі більше місця для першого рядка, що й для другого ("" збігається з "1*"). Ці співвідношення зберігаються, навіть якщо вікно змінюється або пристрій змінюється.
Якщо ви запускаєте додаток зараз, ви не побачите нічого, крім порожньої сторінки, оскільки жодна з областей Сітки не має вмісту. Щоб відобразити сітку, давайте дамо їй якийсь колір.
Крок 3. Колір сітки
Щоб надати колір сітці, ми додали три елементи Border, кожен з яких має інший колір фону. Кожен також призначається рядку і стовпцю батьківської сітки за допомогою атрибутів Grid.Row і Grid.Column. Значення цих атрибутів за замовчуванням дорівнює 0, тому їх не потрібно призначати першій межі. Додайте наступний код в елемент Grid після визначень рядків і стовпців.
<Border Background="#2f5cb6"/>
<Border Grid.Column ="1" Background="#1f3d7a"/>
<Border Grid.Row="1" Grid.ColumnSpan="2" Background="#152951"/>
Зверніть увагу, що для третьої межі ми використовуємо додатковий атрибут Grid.ColumnSpan, який призводить до того, що межа буде охоплювати обидва стовпці в нижньому рядку. Ви можете використовувати Grid.RowSpan у такий самий спосіб, і разом ці атрибути дають змогу охоплювати елемент за будь-якою кількістю рядків і стовпців. Верхній лівий кут такого діапазону завжди є елементом Grid.Column і Grid.Row , зазначеним в атрибутах елемента.
Якщо ви запускаєте додаток, результат має приблизно такий вигляд.

Крок 4. Упорядкування вмісту за допомогою елементів StackPanel
StackPanel - це другий елемент користувацького інтерфейсу, який буде використовуватися для створення додатка погоди. StackPanel є основною частиною багатьох базових макетів застосунків, що дає змогу стекати елементи по вертикалі або горизонтально.
У наступному коді ми створимо два елементи StackPanel і заповнимо кожен із трьох елементів TextBlock. Додайте ці елементи StackPanel у сітку під елементами Border із кроку 3. Це призводить до відображення елементів TextBlock поверх створеної раніше кольорової сітки .
<StackPanel Grid.Column="1" Margin="40,0,0,0" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="25" Text="Today - 64° F"/>
<TextBlock Foreground="White" FontSize="25" Text="Partially Cloudy"/>
<TextBlock Foreground="White" FontSize="25" Text="Precipitation: 25%"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="25" Text="High: 66°" Margin="0,0,20,0"/>
<TextBlock Foreground="White" FontSize="25" Text="Low: 43°" Margin="0,0,20,0"/>
<TextBlock Foreground="White" FontSize="25" Text="Feels like: 63°"/>
</StackPanel>
У першому стеку кожен елемент TextBlock стеків по вертикалі нижче наступного. Це поведінка за замовчуванням StackPanel, тому нам не потрібно задавати атрибут орієнтації . У другому StackPanel потрібно, щоб дочірні елементи стекалися горизонтально зліва направо, тому для атрибута "Орієнтація" задано значення "Горизонтально". Необхідно також задати для атрибута Grid.ColumnSpan значення "2", щоб текст був відцентрований по нижньому краю.
Якщо ви запускаєте додаток зараз, ви побачите щось подібне.

Крок 5. Додавання значка зображення
Нарешті, давайте заповнимо порожній розділ у нашій сітці зображенням, яке представляє поточну погоду, щось, що говорить "частково хмарно".
Завантажте наведене нижче зображення і збережіть його у форматі PNG з ім'ям "частково хмарний".

В Оглядачі рішень клацніть правою кнопкою миші папку "Активи" і виберіть "Додати">Існуючий елемент". Знайдіть partially-cloudy.png у спливаючому браузері, виберіть його і натисніть кнопку "Додати".
Потім у MainPage.xaml додайте наступний елемент Image під StackPanels із кроку 4.
<Image Margin="20" Source="Assets/partially-cloudy.png"/>
Оскільки ми хочемо, щоб зображення було в першому рядку і стовпці, нам не потрібно задавати атрибути Grid.Row або Grid.Column, що дає змогу їм за замовчуванням мати значення "0".
Ось і все! Ви успішно створили макет для простого додатка погоди. Якщо запустити додаток, натиснувши клавішу F5, ви побачите таке:

Якщо вам подобається, спробуйте поекспериментувати з макетом вище і вивчити різні способи подання даних про погоду.