В прошлых темах были рассмотренны генерируемые по умолчанию при создании проекта файлы MainPage.xaml и MainPage.xaml.cs. Если файл MainPage.xaml содержит визуальный интерфейс, то MainPage.xaml.cs предазначен преимущественно для организации программной логики страницы. Но каким образом происходит загрузка XAML?
По умолчанию файл MainPage.xaml.cs содержит следующее определение класса MainPage:
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); } }
В данном случае нас будет интересовать вызов метода InitializeComponent() в конструкторе класса MainPage,
благодаря которому страница получает определенный в связанном xaml-файле графический интерфейс. Метод InitializeComponent()
вызывает другой метод -
LoadFromXaml().
Этот метод извлекает файл XAML (или его скомпилированную бинарную версию) из файла dll, в который скомпилировано приложение.
После извлечения кода графического интерфейса метод инициализирует все объекты, определенные в файле XAML, устанавливает структуру элементов (какой элемент какие элементы содержит), прикрепляет обработчики событий, определенные в файле кода C#, и создает дерево объектов. Таким образом, код из XAML используется для построения интерфейса.
Однако мы сами можем загружать код XAML, причем динамически в процессе выполнения программы, используя тот же самый метод LoadFromXaml(). Подобный способ может применяться, например, при получении кода XAML от веб-сервиса или, когда в зависимости от хода программы необходимо предоставить альтернативные версии интерфейса. Но вместе с тем стоит отметить, что динамическая загрузка XAML снижает производительность приложения, поэтому по возможности ее следует избегать.
Например, добавим в проект новый класс StartPage и определим в нем следующий код:
namespace HelloApp { class StartPage : ContentPage { public StartPage() { string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<ContentPage xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n" + "xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n" + "x:Class=\"HelloApp.StartPage\">\n" + "<Label Text=\"Hello METANIT.COM\" FontSize=\"22\" />" + "</ContentPage>"; this.LoadFromXaml(pageXAML); } } }
Данный класс будет представлять страницу и наследуется от класса ContentPage. В конструкторе класса сначала формируется визуальный интерфейс в виде строки, которая содержит код XML и далее этого код загружается с помощью метода LoadFromXaml().
Установим данную страницу в качестве основной в файле App.xaml.cs:
namespace HelloApp; public partial class App : Application { public App() { InitializeComponent(); MainPage = new StartPage(); // Устанавливаем StartPage в качестве главной } }
После загрузки страницы она будет выглядеть следующим образом:
Может возникнуть необходимость, обращаться к элементам подобного интерфейса в коде C#. Для нахождения элементов по имени можно применять метод FindByName(). Например, изменим тест метки:
namespace HelloApp { class StartPage : ContentPage { public StartPage() { string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<ContentPage xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n" + "xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n" + "x:Class=\"HelloApp.StartPage\">\n" + "<Label x:Name=\"header\" Text=\"Hello METANIT.COM\" FontSize=\"22\" />" + "</ContentPage>"; this.LoadFromXaml(pageXAML); Label header = this.FindByName<Label>("header"); header.Text = ".NET MAUI on METANIT.COM"; } } }
Метод FindByName()
типизированный - он типизируется типом элемента, который надо найти. Например, в даном случае мы ищем элемент Label с именем
header. Соответственно метод FindByName()
тизируется типом Label, а в качестве параметра в него предается строка header. Получив данный элемент, мы можем
проводить с ним различные манипуляции, в частности, в данном случае изменяется текст метки.
Загружать XAML мы можем не только для страницы в целом, но и для отдельных элементов. Например, определим в 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="HelloApp.MainPage"> <VerticalStackLayout> <Label x:Name="header" Text="Hello" FontSize="24" /> <Button Text="Change" Clicked="Button_Clicked" FontSize="24" /> </VerticalStackLayout> </ContentPage>
Здесь определены метка и кнопка. У кнопки задан обработчик события нажатия.
Теперь изменим файл MainPage.xaml.cs:
namespace HelloApp; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } private void Button_Clicked(object sender, System.EventArgs e) { string xaml = "<Label Text=\".NET MAUI\" FontSize=\"24\" />"; header.LoadFromXaml(xaml); } }
В обработчике нажатия кнопки здесь изменяется разметка элемента Label.
И установим данную страницу в файле App.xaml.cs в качестве главной:
namespace HelloApp; public partial class App : Application { public App() { InitializeComponent(); MainPage = new MainPage(); } }
Запустим проект, и при нажатии на кнопку будет динамически изменяться метка: