Когда речь идёт про возможности языка C# или, например, про разработку приложений ASP.NET Core Web API, то всё, что нам необходимо для просмотра результатов работы приложения — консоль. В свою очередь, что касается .NET MAUI, то этот фреймворк всё же, в первую очередь, рассчитан на создание красивых приложение с графическим интерфейсом. Поэтому и мы начнем наше изучение .NET MAUI именно с построения графического интерфейса и основ декларативного языка XAML.
XAML
XAML (eXtensible Application Markup Language) — расширяемый язык разметки для приложений, основанный на XML. Язык разработан Microsoft для декларативного программирования приложений. На текущий момент XAML является фактически центральным звеном для таких технологий и платформ как WPF, UWP и, конечно же, .NET MAUI.
Несмотря на то, что XAML основан на XML, этот язык разметки принципиально отличается как от самого XML, так и от того же HTML, как минимум, тем, что XAML с помощью применяемых в нем объектов «привязан» к типам платформы .NET.
Одним из преимуществ использования XAML в проектах является то, что благодаря тому, что интерфейс приложения разрабатывается на XAML, а логика — на C#, появляется возможность разделить проект на две большие части:
- всё, что связано с графическим интерфейсом разрабатывается дизайнером.
- вся логика работы приложения ложится на плечи разработчика.
С одной стороны, это действительно так — мы имеем такую возможность. И выглядит это довольно заманчиво, на первый взгляд. Однако, не так уж и часто мы можем встретить внутри небольшой команды разработчиков отдельную штатную единицу профессионального дизайнера, который не только владеет инструментами для создания графики, но и знает язык XAML, а значит и владеет информацией о том, что из себя представляют типы данных .NET, как использовать события C# и т.д.. Поэтому, так или иначе, но разработчику проекта необходимо знать не только C#, но и прекрасно разбираться в том, как наиболее эффективно использовать возможности XAML.
Структура XAML-документа
Вернемся к нашему первому приложению .NET MAUI из предыдущей части. В этом приложении уже содержится три файла XAML с которым мы уже знакомы в самых общих чертах:
Для начала, откроем в редакторе файл App.xaml и посмотрим на его структуру:
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FirstApp"
x:Class="FirstApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
На первый взгляд, этот документ ничем не отличается от обычного XML-документа — здесь также прослеживается некоторая структура. Корневой элемент Application содержит вложенные элементы, а также пространства имен и атрибут x:Class. Аналогичным образом, но с другими корневыми элементами, выглядят и два других файла.
Так, AppShell.xaml содержит в качестве корневого элемента Shell:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="FirstApp.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FirstApp"
Shell.FlyoutBehavior="Flyout"
Title="FirstApp">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
Забегая немного вперед, отмечу, что Shell представляет собой страницу-оболочку, которая призвана упростить создание графического интерфейса приложения. Как минимум, благодаря использованию Shell мы получаем уже готовое к использованию боковое меню приложения.
В свою очередь MainPage.xaml представляет собой страницу с неким содержимым:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FirstApp.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Image
Source="dotnet_bot.png"
HeightRequest="185"
Aspect="AspectFit"
SemanticProperties.Description="dot net bot in a hovercraft number nine" />
<Label
Text="Hello, World!"
Style="{StaticResource Headline}"
SemanticProperties.HeadingLevel="Level1" />
<Label
Text="Welcome to .NET Multi-platform App UI"
Style="{StaticResource SubHeadline}"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Fill" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Здесь уже в качестве корневого элемента выступает ContentPage. Даже, если вы мало знакомы с XML, а XAML для нас пока ещё новый язык программирования, зная основные элементы управления, используемые, например, в том же ныне устаревшем .NET Framework, нетрудно догадаться, что на странице MainPage.xaml расположена картинка (элемент Image), текстовая метка (Label) и кнопка (Button). Эти элементы мы можем использовать в XAML-разметке благодаря пространствам имен.
Пространства имен XAML
Подобно XML, в XAML определяются пространства имен — специальные атрибуты корневого элемента документа, имена которых начинаются со строки xmlns. Пространства имен в XAML играют практически ту же роль, что и пространства имен, подключаемые в файлах C#. Благодаря подключенным тем или иным пространствам имен в документа XAML мы получаем возможность использовать объекты .NET. Так, например, посмотрим ещё раз на файл App.xaml. Здесь подключаются три пространства имен:
xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:FirstApp"
Первое пространство имен http://schemas.microsoft.com/dotnet/2021/maui содержит основные элементы для построения графического интерфейса приложения .NET MAUI. Например, те самые кнопки, метки, элементы для вывода картинок и так далее.
Пространство имен http://schemas.microsoft.com/winfx/2009/xaml определяется с помощью атрибута xmlns:x. Здесь содержатся такие важные для использования XAML элементы как Name, Key, Class и так далее. Это пространство имен объявляется с префиксом x, что означает то, что все элементы из этого пространства имен должны начинаться с этого же префикса — x. Так, например, чтобы использовать в разметке элемент x:Class="FirstApp.App" здесь же после пространств имен используется с этим префиксом.
И, наконец, третье пространство имен clr-namespace:FirstApp. Здесь используется префикс local. В принципе, префиксы, обычно, выбираются разработчиком достаточно произвольно. Здесь более важным является префикс в имени пространства — clr-namespace: который указывает на то, что подключается пространство имен CLR с именем FirstApp то есть пространство имен C#, используемое по умолчанию в нашем проекте. Благодаря этому пространству имен мы можем в разметке XAML ссылаться на типы, определяемые в C#-коде нашего приложения. Также, используя пространства имен XAML мы можем подключать в проект пространства имен из других сборок. Например, вот такая запись:
xmlns:controls="clr-namespace:Controls;assembly=MyControlLibrary"
означает, что подключается пространство имен Controls из сборки MyControlLibrary.
Code-behind в XAML
Как можно видеть по представленному выше коду, в разметке XAML отсутствует какая-либо логика приложения — здесь содержится только описание интерфейса приложения и подключаются некие файлы ресурсов. Однако, XAML может содержать логику в виде так называемого code-behind и для этого используются частичные (разделяемые) классы C#. Обратите внимание на то, что с каждым XAML-файлом связан файл с именем, соответсвующим следующему шаблону [имя_файла_xaml].xaml.cs.
В этих файлах и может содержаться логика приложения. Например, вернемся к нашему файлу App.xaml. Откроем также в редакторе кода связанный с этим файлом App.xaml.cs.
namespace FirstApp
{
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
}
}
и попробуем сопоставить разметку XAML с кодом C#:
Обратите внимание на то, что имя класса, определенного в XAML в атрибуте x:Class полностью соответствует имени класса, определенного в файле App.xaml.cs. Так,мы «связываем» класс C# с разметкой XAML. Точно таким же образом связываются классы C# с другими XAML-документами, например класс MainPage и MainPage.xaml. Благодаря такому подходу, мы можем ссылаться в XAML на поля и методы частичного класса. Эта возможность продемонстрирована как раз в MainPage.xaml. Обратите внимание на описание кнопки:
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Fill" />
Здесь x:Name — атрибут, действие которого подобно тому как мы объявляем переменную в коде C#. То есть здесь, используя привычные нам термины C#, мы объявляем переменную с именем CounterBtn и типом Button. Префикс x у атрибута говорит нам о том, что здесь мы задействовали пространство имен http://schemas.microsoft.com/winfx/2009/xaml.
Далее здесь же мы используем атрибут Clicked, который представляет собой событие — клик по кнопке. В качестве значения для этого атрибута выступает имя метода OnCounterClicked, который содержится в классе MainPage (см. файл MainPage.xaml.cs):
namespace FirstApp
{
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
}
Обратите внимание на то, как мы можем ссылаться на объекты и методы C# в XAML (используя атрибут x:Class в корневом элементе документа) и, наоборот — получать объект из разметки XAML (мы добавляем к элементу разметки атрибут x:Name, чтобы сослаться на этот элемент в коде C#).
Итого
Итак, здесь мы рассмотрели самые основные моменты касающиеся языка XAML — из чего состоит документ XAML, для чего используются пространства имен и то, как мы можем связать разметку XAML м кодом C#. На этом наше изучение возможностей XAML не заканчивается и в следующих частях мы будем рассматривать возможности XAML более подробно.