Метод LoadFromXaml и загрузка XAML

Последнее обновление: 30.06.2022

В прошлых темах были рассмотренны генерируемые по умолчанию при создании проекта файлы 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

Однако мы сами можем загружать код 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 в качестве главной
	}
}

После загрузки страницы она будет выглядеть следующим образом:

LoadFromXaml и динамическая загрузка интефейса в .NET MAUI и C#

Может возникнуть необходимость, обращаться к элементам подобного интерфейса в коде 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. Получив данный элемент, мы можем проводить с ним различные манипуляции, в частности, в данном случае изменяется текст метки.

LoadFromXaml и получение элемента через метод FindByName в .NET MAUI и C#

Загружать 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();
	}
}

Запустим проект, и при нажатии на кнопку будет динамически изменяться метка:

LoadFromXaml и обработчики событий в .NET MAUI и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850