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

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

В прошлых темах были рассмотренны генерируемые по умолчанию при создании проекта файлы MainPage.xaml и MainPage.xaml.cs. Если файл MainPage.xaml содержит визуальный интерфейс, то MainPage.xaml.cs предазначен преимущественно для организации программной логики страницы. Но каким образом происходит загрузка XAML?

По умолчанию файл MainPage.xaml.cs содержит следующее определение класса MainPage:

public partial class MainPage : ContentPage
{
	public MainPage()
	{
		InitializeComponent();
	}
}

По сути, все, что делает класс - это вызов метода InitializeComponent(), благодаря которому страница получает определенный в связанном xaml-файле графический интерфейс.

При построении проекта Visual Studio парсит файлы с кодом XAML и генерирует файл, название которого заканчивается на .g.cs (например, MainPage.xaml.g.cs, его можно найи в папке проекта в подкаталоге obj\Debug\netstandard2.0). То есть генерируется обычный класс C#, который содержит определение метода InitializeComponent():

[assembly: global::Xamarin.Forms.Xaml.XamlResourceIdAttribute("HelloApp.MainPage.xaml", "MainPage.xaml", typeof(global::HelloApp.MainPage))]

namespace HelloApp {
    
    [global::Xamarin.Forms.Xaml.XamlFilePathAttribute("MainPage.xaml")]
    public partial class MainPage : global::Xamarin.Forms.ContentPage {
        
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "2.0.0.0")]
        private void InitializeComponent() {
            global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
        }
    }
}

Мы видим, что метод InitializeComponent() вызывает другой метод - LoadFromXaml(). Этот метод извлекает файл XAML (или его скомпилированную бинарную версию) из файла dll, в который скомпилировано приложение.

После извлечения кода графического интерфейса метод инициализирует все объекты, определенные в файле XAML, устанавливает структуру элементов (какой элемент какие элементы содержит), прикрепляет обработчики событий, определенные в файле кода C#, и создает дерево объектов. Таким образом, код из XAML используется для построения интерфейса.

Динамическая загрузка XAML

Однако мы сами можем загружать код XAML, причем динамически в процессе выполнения программы, используя тот же самый метод LoadFromXaml(). Подобный способ может применяться, например, при получении кода XAML от веб-сервиса или, когда в зависимости от хода программы необходимо предоставить альтернативные версии интерфейса. Но вместе с тем стоит отметить, что динамическая загрузка XAML снижает производительность приложения, поэтому по возможности ее следует избегать.

Например, динамически загрузим интерфейс для всей страницы:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace HelloApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
                "<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\n" +
                "xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n" +
                "x:Class=\"HelloApp.MainPage\"\n" +
                "Title=\"Main Page\">\n" +
                "<Label Text=\"XAML in Xamarin\" FontSize=\"36\" />" +
                "</ContentPage>";

            this.LoadFromXaml(pageXAML);
        }
    }
}

Метод LoadFromXaml() является методом расширения, определенным для всех визуальных элементов управления в пространстве имен Xamarin.Forms.Xaml. После загрузки страницы она будет выглядеть следующим образом:

LoadFromXaml в Xamarin

Может возникнуть необходимость, обращаться к элементам подобного интерфейса в коде C#. Для нахождения элементов по имени можно применять метод FindByName(). Например, изменим тест метки:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace HelloApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
                "<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\n" +
                "xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n" +
                "x:Class=\"HelloApp.MainPage\"\n" +
                "Title=\"Main Page\">\n" +
                "<Label x:Name=\"lbl\" Text=\"XAML in Xamarin\" FontSize=\"36\" />" +
                "</ContentPage>";

            this.LoadFromXaml(pageXAML);
            Label lbl = this.FindByName<Label>("lbl");
            lbl.Text = "Changed";
        }
    }
}

Метод FindByName() типизированный - он типизируется типом элемента, который надо найти. Например, в даном случае мы ищем элемент Label с именем lbl. Соответственно метод FindByName() тизируется типом Label, а в качестве параметра в него предается строка lbl.

Загружать XAML мы можем не только для страницы в целом, но и для отдельных элементов. Например, определим в MainPage.xaml следующую разметку:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.MainPage">
    <StackLayout>
        <Label x:Name="lbl" Text="Hello"  FontSize="24" />
        <Button Text="Change" Clicked="Button_Clicked" FontSize="24" />
    </StackLayout>
</ContentPage>

Здесь определены метка и кнопка. У кнопки задан обработчик события нажатия.

Теперь изменим файл MainPage.xaml.cs:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace HelloApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Button_Clicked(object sender, System.EventArgs e)
        {
            string xaml = "<Label Text=\"Xamarin Forms\" FontSize=\"24\" />";
            lbl.LoadFromXaml(xaml);
        }
    }
}

В обработчике нажатия кнопки здесь изменяется разметка элемента Label.

LoadFromXaml в Xamarin Forms
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850