Тема 1.3: Основи XAML
Вступ
Вітаємо! Ми вже знаємо, що таке WinUI 3 і як налаштувати Visual Studio. Тепер час зануритися в створення інтерфейсу користувача. У WinUI 3 за це відповідає XAML — мова розмітки, яка дозволяє описувати UI просто і зручно. У цій темі ми розберемо, що таке XAML, як він працює, і створимо простий інтерфейс із кнопкою та текстовим полем. Готові малювати вікна кодом? Тоді почнімо!
Навчальний матеріал по XAML для WinUI 3
Огляд XAML
XAML (Extensible Application Markup Language) — це декларативна мова розмітки, яка використовується для опису користувацького інтерфейсу (UI) у додатках Windows. Хоча XAML спочатку був розроблений для WPF (Windows Presentation Foundation), він є окремою технологією, яка адаптована в WinUI 3 для створення сучасних настільних додатків у рамках Windows App SDK. У цьому матеріалі ми зосередимося на XAML у контексті WinUI 3, але також порівняємо його з WPF, де це доречно.
XAML дозволяє описувати елементи UI за допомогою розмітки, відокремлюючи їх від логіки поведінки, яка розміщується в окремих файлах із програмним кодом (модель code-behind). На відміну від традиційних мов розмітки, таких як HTML, XAML безпосередньо описує створення об’єктів і тісно пов’язаний із системою типів .NET. Це забезпечує чітке відображення між розміткою та об’єктно-орієнтованим кодом.
Використання XAML сприяє поділу обов’язків між дизайнерами UI та розробниками логіки, дозволяючи їм працювати паралельно з різними інструментами (наприклад, Visual Studio для коду та Blend для дизайну). XAML-файли зазвичай мають розширення .xaml і зберігаються в текстовому форматі, найчастіше з кодуванням UTF-8.
Відмінність від WPF: У WPF XAML був частиною ширшої платформи, яка включала глибоку інтеграцію з .NET Framework. У WinUI 3 XAML працює в рамках Windows App SDK, який підтримує як .NET (наприклад, .NET 6/8), так і C++ із Win32, що робить його більш гнучким для настільних додатків.
1. Синтаксис XAML
Синтаксис XAML базується на XML, тому він знайомий тим, хто працював із XML. Однак XAML додає власні концепції, які розширюють можливості XML для створення об’єктів UI. У цьому розділі ми розглянемо основи синтаксису, зосередившись на WinUI 3, із прикладами та поясненнями.
Примітка: Більшість прикладів будуть фрагментами, а не повними файлами, щоб зосередитися на конкретних аспектах синтаксису. Повні приклади з’являться там, де це необхідно для демонстрації взаємодії частин.
1.1. Чутливість до регістру
XAML, як і XML, є чутливим до регістру. Це пояснюється тим, що імена елементів і атрибутів у XAML відповідають типам і властивостям у коді, які також чутливі до регістру (наприклад, Button ≠ button).
Приклад:
<Button Content="Click me"/> <!-- Коректно -->
<button content="Click me"/> <!-- Помилка -->
Порівняння з WPF: Поведінка ідентична в WPF і WinUI 3.
1.2. Елемент
Елементи в XAML представляють екземпляри об’єктів, які створюються під час обробки розмітки XAML-парсером. Кожен елемент відповідає типу даних (класу), а для його створення використовується конструктор за замовчуванням.
Синтаксис:
<TypeName>Content</TypeName>
<TypeName>— назва типу (наприклад,Button).Content— вміст елемента (текст або дочірні елементи).
Якщо вмісту немає, можна використовувати самозакривний тег:
<TypeName/>
Приклад:
<Grid>
<TextBox/>
</Grid>
- Створюється об’єкт
Gridіз простору іменMicrosoft.UI.Xaml.Controls. - Усередині нього створюється
TextBoxяк дочірній елемент.
Еквівалент у C# (WinUI 3):
using Microsoft.UI.Xaml.Controls;
var grid = new Grid();
var textBox = new TextBox();
grid.Children.Add(textBox);
Порівняння з WPF: У WPF простір імен був System.Windows.Controls, а в WinUI 3 — Microsoft.UI.Xaml.Controls. Логіка створення об’єктів однакова, але типи належать до різних бібліотек.
Вміст: Залежить від типу. Наприклад, Button у WinUI 3 може мати текст або один дочірній елемент як вміст, тоді як Grid підтримує кілька дочірніх елементів у колекції Children.
1.3. Атрибут
Атрибути в XAML задають значення властивостей об’єктів. Вони записуються у форматі PropertyName="Value".
Синтаксис:
<TypeName PropertyName="Value">Content</TypeName>
- Кілька атрибутів розділяються пробілом, порядок не має значення.
Приклад:
<Button Height="30" Width="100">Yes</Button>
Еквівалент у C#:
var button = new Button { Height = 30, Width = 100, Content = "Yes" };
Обробники подій: Атрибути також використовуються для прив’язки подій до методів у code-behind:
<Button Click="Button_Click">OK</Button>
Click— подія,Button_Click— назва методу в code-behind.
Обмеження: Одна властивість не може бути визначена двічі для одного елемента:
<Button Height="100" Height="50"/> <!-- Помилка -->
Порівняння з WPF: Синтаксис ідентичний, але в WinUI 3 методи обробників подій у code-behind належать до простору імен Microsoft.UI.Xaml, а не System.Windows.
1.4. Елемент-властивість
Для складних значень властивостей (наприклад, об’єктів із власними властивостями) використовується синтаксис елемента-властивості: <TypeName.PropertyName>.
Синтаксис:
<TypeName>
<TypeName.PropertyName>
<!-- Вміст -->
</TypeName.PropertyName>
</TypeName>
Приклад:
<TextBox FontFamily="Consolas" FontSize="20" Foreground="Yellow">
<TextBox.Background>
<SolidColorBrush Color="Aqua" Opacity="0.5"/>
</TextBox.Background>
</TextBox>
Еквівалент у C#:
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
var textBox = new TextBox
{
FontFamily = new FontFamily("Consolas"),
FontSize = 20,
Foreground = new SolidColorBrush(Colors.Yellow),
Background = new SolidColorBrush { Color = Colors.Aqua, Opacity = 0.5 }
};
Комбінація з атрибутами:
<TextBox Foreground="Red">
<TextBox.FontSize>20</TextBox.FontSize>
</TextBox>
Обмеження: Одна властивість не може бути визначена одночасно як атрибут і як елемент-властивість:
<TextBox Foreground="Red">
<TextBox.Foreground>Red</TextBox.Foreground> <!-- Помилка -->
</TextBox>
Порівняння з WPF: Логіка та синтаксис однакові, але в WinUI 3 використовуються типи з Microsoft.UI.Xaml.Media замість System.Windows.Media.
1. Властивість-колекція
Для властивостей, які є колекціями, XAML дозволяє додавати елементи напряму або через явне визначення колекції.
Синтаксис (повний):
<TypeName>
<TypeName.CollectionPropertyName>
<CollectionName>
<Item1/>
<Item2/>
</CollectionName>
</TypeName.CollectionPropertyName>
</TypeName>
Синтаксис (спрощений):
<TypeName>
<TypeName.CollectionPropertyName>
<Item1/>
<Item2/>
</TypeName.CollectionPropertyName>
</TypeName>
Приклад:
<TextBox>
<TextBox.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="Red" Offset="0.0"/>
<GradientStop Color="Pink" Offset="1.0"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</TextBox.Background>
</TextBox>
Еквівалент у C#:
var textBox = new TextBox
{
Background = new LinearGradientBrush
{
GradientStops = { new GradientStop { Color = Colors.Red, Offset = 0.0 }, new GradientStop { Color = Colors.Pink, Offset = 1.0 } }
}
};
Особливості:
- Спрощений синтаксис викликає
getколекції та додає елементи черезAdd. - Повний синтаксис створює нову колекцію, що може бути важливим, якщо потрібно замінити існуючу.
Порівняння з WPF: У WPF типи колекцій (наприклад, GradientStopCollection) належать до System.Windows.Media, а в WinUI 3 — до Microsoft.UI.Xaml.Media. Поведінка однакова.
1.6. Властивість «вміст»
Кожен клас може позначити одну властивість як вміст (зазвичай Content), куди автоматично записується текст або дочірні елементи.
Приклад:
<Button>Click me</Button>
<!-- Еквівалент -->
<Button>
<Button.Content>Click me</Button.Content>
</Button>
Порядок: Вміст має бути або перед усіма елементами-властивостями, або після них:
<Button>
<Button.Background>Red</Button.Background>
Click me
</Button>
Помилка:
<Button>
Click
<Button.Background>Red</Button.Background>
me <!-- Помилка -->
</Button>
Порівняння з WPF: Логіка та синтаксис ідентичні.
1.7. Комбінація властивості «вміст» і властивості-колекції
Якщо властивість вмісту є колекцією, дочірні елементи додаються до неї автоматично.
Приклад:
<StackPanel>
<Button>Button 1</Button>
<Button>Button 2</Button>
</StackPanel>
Повна форма:
<StackPanel>
<StackPanel.Children>
<Button>Button 1</Button>
<Button>Button 2</Button>
</StackPanel.Children>
</StackPanel>
Еквівалент у C#:
var stackPanel = new StackPanel();
stackPanel.Children.Add(new Button { Content = "Button 1" });
stackPanel.Children.Add(new Button { Content = "Button 2" });
Порівняння з WPF: Ідентично, але в WinUI 3 StackPanel із Microsoft.UI.Xaml.Controls.
1.8. Приєднана властивість
Приєднані властивості дозволяють одному типу визначати властивість, яку можна використовувати в іншому типі.
Синтаксис:
<TypeName AnotherTypeName.PropertyName="Value"/>
Приклад:
<Grid>
<TextBox Grid.Row="0" Grid.Column="0"/>
</Grid>
Еквівалент у C#:
var grid = new Grid();
var textBox = new TextBox();
grid.Children.Add(textBox);
Grid.SetRow(textBox, 0);
Grid.SetColumn(textBox, 0);
Елемент-властивість:
<TextBox>
<Grid.Row>0</Grid.Row>
</TextBox>
Обмеження:
<TextBox Grid.Row="0">
<Grid.Row>0</Grid.Row> <!-- Помилка -->
</TextBox>
Порівняння з WPF: Ідентично, але простір імен у WinUI 3 — Microsoft.UI.Xaml.Controls.
1.9. Перетворювач типу
Перетворювачі типів дозволяють задавати складні значення як рядки, які автоматично конвертуються в об’єкти.
Приклад:
<Button BorderThickness="15,5,10,10">Submit</Button>
<!-- Еквівалент -->
<Button>
<Button.BorderThickness>
<Thickness Left="15" Top="5" Right="10" Bottom="10"/>
</Button.BorderThickness>
</Button>
Порівняння з WPF: Ідентично, але тип Thickness у WinUI 3 із Microsoft.UI.Xaml.
1.10. Розширення розмітки
Розширення розмітки дозволяють отримувати значення динамічно під час виконання.
Синтаксис:
<TypeName PropertyName="{ExtensionName Argument}"/>
Приклад:
<Button Style="{StaticResource MyButtonStyle}">OK</Button>
Варіанти:
<Button Style="{StaticResource MyButtonStyle, Property=Value}"/>
<Button Style="{StaticResource}"/>
Порівняння з WPF: Ідентично, але в WinUI 3 використовуються ресурси з Microsoft.UI.Xaml.
1.11. Кореневий елемент і простори імен
XAML-файл має один кореневий елемент (наприклад, Window) і визначає простори імен через xmlns.
Приклад:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button>Click</Button>
</Window>
Кастомний простір імен:
<Window xmlns:custom="clr-namespace:MyApp.Controls">
<custom:MyControl/>
</Window>
Порівняння з WPF: Ідентично, але в WinUI 3 кореневий елемент часто Window із Microsoft.UI.Xaml.
2. Модель Code-Behind
Модель code-behind пов’язує XAML із кодом (наприклад, C#). XAML описує UI, а код — логіку.
Приклад:
<Button x:Name="myButton" Click="MyButton_Click">Click</Button>
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
private void MyButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "Clicked";
}
}
Вимоги:
- Клас у code-behind успадковується від кореневого елемента XAML.
- Обробники подій — екземплярні методи.
Порівняння з WPF: У WPF кореневий клас — System.Windows.Window, у WinUI 3 — Microsoft.UI.Xaml.Window.
2.1. Атрибути Name і x:Name
x:Name— XAML-концепція, створює поле в code-behind.Name— властивість об’єкта в WinUI 3, псевдонім дляx:Name.
Приклад:
<Button x:Name="myButton"/>
<!-- або -->
<Button Name="myButton"/>
Порівняння з WPF: Ідентично, але в WPF Name частіше використовувався через історичні причини.
Поради з найкращих практик
Ось короткі поради з найкращих практик для XAML у контексті WinUI 3, стандарти іменування та інформація про форматувальники в Visual Studio.
Найкращі практики для XAML
- Розділяйте UI та логіку:
- Використовуйте модель code-behind або MVVM для відокремлення розмітки від бізнес-логіки.
- Уникайте складної логіки в обробниках подій у XAML-файлах.
- Оптимізуйте структуру:
- Уникайте глибокої вкладеності елементів — це ускладнює читання та продуктивність.
- Використовуйте контейнери (
Grid,StackPanel) розумно, уникаючи надлишкових обгорток.
- Використовуйте ресурси:
- Визначайте стилі, шаблони та кольори в
ResourceDictionaryдля повторного використання. - Приклад:
<Window.Resources> <Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Blue"/> </Style> </Window.Resources>
- Визначайте стилі, шаблони та кольори в
- Мінімізуйте дублювання:
- Використовуйте
DataTemplateдля повторюваних елементів у списках. - Уникайте копіювання однакових атрибутів — винесіть їх у стилі.
- Використовуйте
- Оптимізація продуктивності:
- Уникайте надмірного використання
Bindingтам, де достатньо статичних значень. - Використовуйте
x:Loadдля відкладеного завантаження елементів, якщо вони не потрібні одразу.
- Уникайте надмірного використання
- Коментарі та читабельність:
- Додавайте коментарі для складних частин:
<!-- Головна панель навігації --> <StackPanel Orientation="Horizontal">
- Додавайте коментарі для складних частин:
- Локалізація:
- Використовуйте
x:Uidдля прив’язки до ресурсів локалізації:<Button x:Uid="SubmitButton" Content="Submit"/>
- Використовуйте
Форматувальник XAML у Visual Studio
Visual Studio має вбудований форматувальник для XAML:
- Як увімкнути:
- Перейдіть до
Tools > Options > Text Editor > XAML > Formatting. - Налаштуйте параметри (наприклад, відступи, перенесення рядків).
- Перейдіть до
- Гарячі клавіші:
Ctrl + K, Ctrl + D— форматує весь документ.Ctrl + K, Ctrl + F— форматує виділений фрагмент.
- XAML Styler: Для розширених можливостей встановіть плагін "XAML Styler" через Marketplace. Він дозволяє кастомізувати правила форматування (наприклад, порядок атрибутів).
Стандарти іменування
- Елементи (
x:Name):- Використовуйте описові імена з типом у кінці:
submitButton,userNameTextBox. - Префікс зазвичай опускається, але може бути корисним у великих проєктах (наприклад,
btnSubmit).
- Використовуйте описові імена з типом у кінці:
- Ресурси (
x:Key):- Починайте з великої літери, додавайте суфікс за типом:
ButtonStyle,PrimaryColorBrush.
- Починайте з великої літери, додавайте суфікс за типом:
- Обробники подій:
- Формат:
<Елемент>_<Подія>(наприклад,submitButton_Click).
- Формат:
- Простори імен (
xmlns):- Короткі, зрозумілі псевдоніми:
controlsдля кастомних контролів,xдля стандартного XAML.
- Короткі, зрозумілі псевдоніми:
Приклад:
<Window xmlns:custom="clr-namespace:MyApp.Controls">
<Button x:Name="submitButton" Click="submitButton_Click" Style="{StaticResource ButtonStyle}"/>
</Window>
У WinUI 3 і WPF немає строгого офіційного стандарту від Microsoft щодо регістру першого символу в іменах елементів (x:Name), але є певні тенденції та конвенції, які формуються спільнотою розробників і практиками в документації. Давайте розберемо це коротко.
WinUI 3
- Тенденція: У сучасних прикладах для WinUI 3 (зокрема в документації Windows App SDK і шаблонах Visual Studio) частіше використовують імена з малої літери на початку (
camelCase). Наприклад:<Button x:Name="submitButton" Content="Submit"/> - Причина:
- WinUI 3 орієнтований на сучасні практики .NET, де
camelCaseє стандартом для локальних змінних і полів у C#. Оскількиx:Nameгенерує поле в code-behind, багато розробників адаптували цей стиль. - Спрощення узгодженості з іншими платформами (наприклад, UWP), де також переважає
camelCase.
- WinUI 3 орієнтований на сучасні практики .NET, де
- Гнучкість: Проте це не є жорстким правилом. Ви можете використовувати
PascalCase(з великої літери), якщо це відповідає внутрішнім стандартам вашої команди.
WPF
- Тенденція: У WPF частіше зустрічалися імена з великої літери на початку (
PascalCase), особливо в ранніх прикладах і книгах (наприклад, 2006–2010 роки). Наприклад:<Button x:Name="SubmitButton" Content="Submit"/> - Причина:
- WPF з’явився в епоху .NET Framework, коли
PascalCaseбув поширеним для іменування властивостей і публічних членів класу. Розробники переносили цей стиль наx:Name. - Більш "об’єктно-орієнтований" підхід до іменування, де елементи UI сприймалися як значущі об’єкти.
- WPF з’явився в епоху .NET Framework, коли
- Еволюція: З часом у WPF також почали з’являтися приклади з
camelCase, особливо в проєктах, що мігрували до .NET Core або використовували MVVM.
Порівняння та рекомендація
- WinUI 3: Переважає
camelCase(наприклад,submitButton), що відображає сучасні тенденції в .NET-екосистемі. - WPF: Історично частіше
PascalCase(наприклад,SubmitButton), але це не було обов’язковим.
Рекомендація:
- Для WinUI 3 дотримуйтесь
camelCase(з малої літери), щоб відповідати сучасним зразкам і консистентності з C# полями:<TextBox x:Name="userNameTextBox"/> - Якщо ви мігруєте з WPF або працюєте в команді з усталеними стандартами, можете зберегти
PascalCaseдля консистентності. - Головне — узгодженість у межах проєкту. Виберіть один стиль і дотримуйтесь його всюди.
Приклад у контексті
WinUI 3 (camelCase):
<Window>
<StackPanel>
<TextBox x:Name="userNameTextBox"/>
<Button x:Name="submitButton" Click="submitButton_Click"/>
</StackPanel>
</Window>
WPF (PascalCase, історично):
<Window>
<StackPanel>
<TextBox x:Name="UserNameTextBox"/>
<Button x:Name="SubmitButton" Click="SubmitButton_Click"/>
</StackPanel>
</Window>
Отже, у WinUI 3 дійсно частіше прийнято використовувати camelCase, тоді як у WPF історично переважав PascalCase. Але це більше питання стилю, ніж жорсткої вимоги.
Питання для роздумів
- Чим XAML кращий за створення UI повністю в C#?
- Як би ви додали другу кнопку, щоб очистити текст?
Ресурси
- Документація XAML у WinUI: learn.microsoft.com/windows/apps/winui/winui3/xaml
- Список контролів: learn.microsoft.com/windows/apps/design/controls
Висновок
Ви освоїли основи XAML у WinUI 3: від синтаксису до створення простого інтерактивного інтерфейсу. Ми навчилися працювати з контролами (TextBlock, Button, TextBox) і прив’язувати події до C#. Наступного разу ми розберемо макети, щоб наш UI став ще красивішим і структурованішим. Чудова робота!
Ось практичне завдання по XAML для WinUI 3, яке займе приблизно 30 хвилин. Воно просте, але охоплює основи роботи з розміткою, стилями та подіями.
Практичне завдання: "Калькулятор додавання"
Мета: Створити простий додаток у WinUI 3, який дозволяє користувачу ввести два числа, натиснути кнопку "Додати" та отримати результат у текстовому полі.
Час: ~30 хвилин
Рівень: Початковий
Інструменти: Visual Studio 2022 із шаблоном "Blank App, Packaged (WinUI 3 in Desktop)".
Опис завдання
- Інтерфейс:
- Два поля введення (
TextBox) для чисел. - Кнопка (
Button) з написом "Додати". - Текстове поле (
TextBlock) для відображення результату. - Усе розміщено в
StackPanelдля вертикального вирівнювання.
- Два поля введення (
- Функціональність:
- При натисканні кнопки додаток зчитує числа з полів, додає їх і виводить результат.
- Якщо введено некоректні дані (не числа), виводиться повідомлення "Помилка".
- Стилізація:
- Додайте стиль для кнопки (наприклад, зелений фон).
- Задайте відступи для елементів.
Крок за кроком
- Створіть проєкт:
- У Visual Studio виберіть шаблон "Blank App, Packaged (WinUI 3 in Desktop)" із C#.
- Назвіть проєкт, наприклад,
SimpleCalculator.
- Оновіть MainWindow.xaml:
- Оновіть MainWindow.xaml.cs:
- Додайте логіку обробки події кнопки
- Запустіть і перевірте:
- Натисніть F5, введіть два числа (наприклад, "5" і "3"), натисніть "Додати".
- Перевірте, чи відображається "Результат: 8".
- Спробуйте ввести некоректні дані (наприклад, "abc") і перевірте повідомлення про помилку.
Очікуваний результат
- Інтерфейс із двома полями введення, зеленою кнопкою та текстовим полем для результату.
- Коректне додавання чисел або виведення помилки при некоректному вводі.