Часть 1. Начало работы с XAML

Download Sample Скачайте пример

Xamarin.Forms В приложении XAML в основном используется для определения визуального содержимого страницы и работает вместе с файлом кода C#.

Файл программной части предоставляет поддержку кода для разметки. Вместе эти два файла вносят вклад в новое определение класса, включающее дочерние представления и инициализацию свойств. В XAML-файле классы и свойства ссылаются на XML-элементы и атрибуты, а также устанавливаются связи между разметкой и кодом.

Создание решения

Чтобы начать редактирование первого XAML-файла, используйте Visual Studio или Visual Studio для Mac для создания нового Xamarin.Forms решения. (Выберите вкладку ниже, соответствующую вашей среде.)

В Windows запустите Visual Studio 2019 и в окне запуска нажмите кнопку "Создать проект", чтобы создать новый проект :

New Solution Window

В окне Создать проект в раскрывающемся списке Тип проекта выберите Мобильное приложение, а затем выберите шаблон Мобильное приложение (Xamarin.Forms) и нажмите кнопку Далее:

New Project Window

В окне "Настройка нового проекта" задайте имяпроекта в XamlSamples (или любой другой вариант) и нажмите кнопку "Создать".

В диалоговом окне "Новое кроссплатформенное приложение" нажмите кнопку "Пустой" и нажмите кнопку "ОК":

New App Dialog

В решении создаются четыре проекта: библиотека XamlSamples .NET Standard, XamlSamples.Android, XamlSamples.iOS и решение универсальная платформа Windows XamlSamples.UWP.

После создания решения XamlSamples может потребоваться протестировать среду разработки, выбрав различные проекты платформы в качестве проекта запуска решения и создав простое приложение, созданное шаблоном проекта на мобильных эмуляторах или реальных устройствах.

Если вам не нужно писать код для конкретной платформы, общий проект библиотеки XAMLSamples .NET Standard находится в том месте, где вы будете тратить практически все время программирования. Эти статьи не будут уходить за пределы этого проекта.

Анатомия XAML-файла

В библиотеке XAMLSamples .NET Standard есть пара файлов со следующими именами:

  • App.xaml, XAML-файл и
  • App.xaml.cs, файл кода C#, связанный с XAML-файлом.

Чтобы увидеть файл программной части, необходимо щелкнуть стрелку рядом с App.xaml .

Как App.xaml , так и App.xaml.cs вносят свой вклад в класс с именем App , производным от Application. Большинство других классов с XAML-файлами вносят вклад в класс, производный от ContentPage; эти файлы используют XAML для определения визуального содержимого всей страницы. Это верно для других двух файлов в проекте XamlSamples :

  • MainPage.xaml, XAML-файл и
  • MainPage.xaml.cs файл кода C#.

Файл MainPage.xaml выглядит следующим образом (хотя форматирование может быть немного другим):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin Forms!"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
    </StackLayout>

</ContentPage>

Два объявления пространстваxmlns имен XML относятся к URI, первый, казалось бы, на веб-сайте Xamarin и втором в Microsoft. Не беспокойтесь проверка, на что указывают эти URI. Там ничего нет. Они просто URI принадлежат Xamarin и Майкрософт, и они в основном работают в качестве идентификаторов версий.

Первое объявление пространства имен XML означает, что теги, определенные в XAML-файле без префикса, ссылаются на классы, Xamarin.Formsнапример ContentPage. Второе объявление пространства имен определяет префикс x. Это используется для нескольких элементов и атрибутов, встроенных в xaml и поддерживаемых другими реализациями XAML. Однако эти элементы и атрибуты немного отличаются в зависимости от года, внедренного в URI. Xamarin.Forms поддерживает спецификацию XAML 2009, но не все.

Объявление local пространства имен позволяет получить доступ к другим классам из проекта библиотеки .NET Standard.

В конце этого первого тега x префикс используется для атрибута с именем Class. Так как использование этого x префикса является практически универсальным для пространства имен XAML, такие атрибуты XAML, как Class почти всегда называются x:Class.

Атрибут x:Class задает полное имя класса .NET: MainPage класс в XamlSamples пространстве имен. Это означает, что этот XAML-файл определяет новый класс, именованный MainPage в XamlSamples пространстве имен, наследуемом x:Class от ContentPageтега, в котором отображается атрибут.

Атрибут x:Class может отображаться только в корневом элементе XAML-файла для определения производного класса C#. Это единственный новый класс, определенный в XAML-файле. Все остальное, которое отображается в XAML-файле, просто создается из существующих классов и инициализировано.

Файл MainPage.xaml.cs выглядит следующим образом (помимо неиспользуемых using директив):

using Xamarin.Forms;

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

Класс MainPage является производным от ContentPageкласса, но обратите внимание на partial определение класса. Это предполагает, что должно быть другое определение частичного класса для MainPage, но где это? И что такое InitializeComponent метод?

Когда Visual Studio создает проект, он анализирует XAML-файл для создания файла кода C#. Если вы посмотрите в каталоге XamlSamples\XamlSamples\obj\Debug , вы найдете файл с именем XamlSamples.MainPage.xaml.g.cs. Значение "g" означает созданный. Это другое определение частичного MainPageInitializeComponent класса, содержащее определение метода, вызываемого конструктором MainPage . Затем эти два определения частичного MainPage класса можно скомпилировать вместе. В зависимости от того, компилируется ли XAML-файл или двоичный формат XAML-файла, внедряется в исполняемый файл.

Во время выполнения код в конкретном проекте платформы вызывает LoadApplication метод, передавая в него новый экземпляр App класса в библиотеке .NET Standard. Конструктор App классов создает экземпляры MainPage. Конструктор этого класса InitializeComponentвызывает метод, который затем вызывает LoadFromXaml метод, который извлекает XAML-файл (или его скомпилированный двоичный файл) из библиотеки .NET Standard. LoadFromXaml Инициализирует все объекты, определенные в XAML-файле, подключает их все вместе в отношениях родительского дочернего элемента, присоединяет обработчики событий, определенные в коде, к событиям, заданным в XAML-файле, и задает результирующий дерево объектов в качестве содержимого страницы.

Хотя обычно вам не нужно тратить много времени на созданные файлы кода, иногда исключения среды выполнения создаются в коде в созданных файлах, поэтому их следует ознакомиться с ними.

При компиляции и запуске этой программы Label элемент отображается в центре страницы, как предполагает XAML:

Default Xamarin.Forms display

Для более интересных визуальных элементов все, что вам нужно, является более интересным XAML.

Добавление новых страниц XAML

Чтобы добавить в проект другие классы на основе ContentPage XAML, выберите проект библиотеки XamlSamples .NET Standard, щелкните правой кнопкой мыши и выберите команду "Добавить > новый элемент...". В диалоговом окне "Добавление нового элемента" выберите страницу содержимого элементов Visual C# >>Xamarin.Forms(не страницу содержимого (C#), которая создает страницу только для кода или представление содержимого, которое не является страницей. Укажите имя страницы, например HelloXamlPage:

Add New Item Dialog

В проект добавляются два файла HelloXamlPage.xaml и файл программной части HelloXamlPage.xaml.cs.

Настройка содержимого страницы

Измените файл HelloXamlPage.xaml , чтобы только теги были для ContentPage и ContentPage.Content:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage">
    <ContentPage.Content>

    </ContentPage.Content>
</ContentPage>

Теги ContentPage.Content являются частью уникального синтаксиса XAML. Сначала они могут быть недопустимыми XML, но они являются законными. Период не является особым символом в XML.

Теги ContentPage.Content называются тегами элементов свойства. Content — это свойство ContentPage, и обычно присваивается одному представлению или макету с дочерними представлениями. Обычно свойства становятся атрибутами в XAML, но трудно задать Content атрибут сложному объекту. По этой причине свойство выражается как XML-элемент, состоящий из имени класса и имени свойства, разделенного точкой. Content Теперь свойство можно задать между тегамиContentPage.Content, как показано ниже.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page">
    <ContentPage.Content>

        <Label Text="Hello, XAML!"
               VerticalOptions="Center"
               HorizontalTextAlignment="Center"
               Rotation="-15"
               IsVisible="true"
               FontSize="Large"
               FontAttributes="Bold"
               TextColor="Blue" />

    </ContentPage.Content>
</ContentPage>

Обратите внимание, что Title атрибут установлен в корневом теге.

В настоящее время связь между классами, свойствами и XML должна быть очевидной: Xamarin.Forms класс (например ContentPage , или Label) отображается в XAML-файле в виде XML-элемента. Свойства этого класса, включая TitleContentPage и семь свойств Label, обычно отображаются как XML-атрибуты.

Для задания значений этих свойств существует множество сочетаний клавиш. Некоторые свойства являются базовыми типами данных: например, Title свойства имеют типDoubleString, Rotation тип и IsVisible (который true по умолчанию и задан здесь только для иллюстрации) имеет типBoolean.Text

Свойство HorizontalTextAlignment имеет тип TextAlignment, который является перечислением. Для свойства любого типа перечисления необходимо указать имя члена.

Однако для свойств более сложных типов преобразователи используются для анализа XAML. Это классы, Xamarin.Forms производные от TypeConverter. Многие из них являются общедоступными классами, но некоторые из них не являются. Для этого конкретного XAML-файла некоторые из этих классов играют роль за кулисами:

  • LayoutOptionsConverterVerticalOptions для свойства
  • FontSizeConverterFontSize для свойства
  • ColorTypeConverterTextColor для свойства

Эти преобразователи управляют допустимым синтаксисом параметров свойств.

Может ThicknessTypeConverter обрабатывать одно, два или четыре числа, разделенные запятыми. Если указано одно число, оно применяется ко всем четырем сторонам. С двумя числами первый — левый и правый, а второй — верхний и нижний. Четыре числа находятся в порядке слева, сверху, справа и внизу.

Имена LayoutOptionsConverter общедоступных статических полей LayoutOptions структуры можно преобразовать в значения типа LayoutOptions.

Может FontSizeConverter обрабатывать NamedSize элемент или числовый размер шрифта.

Принимает ColorTypeConverter имена общедоступных статических полей Color структуры или шестнадцатеричных значений RGB, с альфа-каналом или без него, перед которым предшествует знак числа (#). Вот синтаксис без альфа-канала:

TextColor="#rrggbb"

Каждая из маленьких букв — шестнадцатеричная цифра. Вот как включается альфа-канал:

TextColor="#aarrggbb">

Для альфа-канала следует помнить, что FF полностью непрозрачн и 00 полностью прозрачны.

Два других формата позволяют указать только одну шестнадцатеричную цифру для каждого канала:

TextColor="#rgb" TextColor="#argb"

В таких случаях цифра повторяется для формирования значения. Например, #CF3 — это цвет RGB CC-FF-33.

При запуске программы MainPage XamlSamples отображается. Чтобы увидеть новое HelloXamlPage , можно задать его как новую страницу запуска в файле App.xaml.cs или перейти на новую страницу из MainPage.

Чтобы реализовать навигацию, сначала измените код в конструкторе App.xaml.cs , чтобы NavigationPage создать объект:

public App()
{
    InitializeComponent();
    MainPage = new NavigationPage(new MainPage());
}

В конструкторе MainPage.xaml.cs можно создать простой Button и использовать обработчик событий для перехода к HelloXamlPage:

public MainPage()
{
    InitializeComponent();

    Button button = new Button
    {
        Text = "Navigate!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

    button.Clicked += async (sender, args) =>
    {
        await Navigation.PushAsync(new HelloXamlPage());
    };

    Content = button;
}

Content Установка свойства страницы заменяет параметр Content свойства в XAML-файле. При компиляции и развертывании новой версии этой программы на экране появится кнопка. При нажатии клавиши переход к ней выполняется HelloXamlPage. Ниже приведена результирующая страница на i Телефон, Android и UWP:

Rotated Label Text

Вы можете вернуться к MainPage кнопке < "Назад " в iOS, используя стрелку влево в верхней части страницы или в нижней части телефона в Android или с помощью стрелки влево в верхней части страницы в Windows 10.

Вы можете поэкспериментировать с XAML для различных способов отрисовки Label. Если необходимо внедрить любые символы Юникода в текст, можно использовать стандартный синтаксис XML. Например, чтобы поместить приветствие в смарт-кавычки, используйте следующую команду:

<Label Text="&#x201C;Hello, XAML!&#x201D;" … />

Вот как выглядит:

Rotated Label Text with Unicode Characters

Взаимодействие XAML и кода

Пример HelloXamlPage содержит только один на Label странице, но это очень необычно. Большинство ContentPage производных задают Content свойство макету определенного типа, например StackLayout. Свойство ChildrenStackLayout определяется IList<View> типом, но на самом деле является объектом типа ElementCollection<View>, и эта коллекция может быть заполнена несколькими представлениями или другими макетами. В XAML эти отношения с родительским дочерним элементом устанавливаются с обычной XML-иерархией. Ниже приведен XAML-файл для новой страницы с именем XamlPlusCodePage:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Этот XAML-файл синтаксически завершен и выглядит следующим образом:

Multiple Controls on a Page

Однако, скорее всего, вы считаете, что эта программа будет функционально недостаточной. Slider Возможно, это должно Label привести к отображению текущего значения, иButton, вероятно, предназначено для выполнения чего-то в программе.

Как вы увидите в части 4. Основные сведения о привязке данных— задание отображения Slider значения, использующее Label значение, можно полностью обрабатывать в XAML с привязкой данных. Но сначала полезно увидеть решение кода. Даже поэтому для обработки щелчка Button определенно требуется код. Это означает, что файл программной части должен XamlPlusCodePage содержать обработчики для ValueChanged события Slider и Clicked события Buttonсобытия. Давайте добавим их:

namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

Эти обработчики событий не должны быть общедоступными.

Обратно в XAML-файл Slider и Button теги должны включать атрибуты для ValueChanged и Clicked событий, ссылающихся на эти обработчики:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand"
                ValueChanged="OnSliderValueChanged" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Clicked="OnButtonClicked" />
    </StackLayout>
</ContentPage>

Обратите внимание, что назначение обработчика событию имеет тот же синтаксис, что и назначение значения свойству.

Если обработчик ValueChanged события будет использовать Label для отображения текущего Slider значения, обработчик должен ссылаться на этот объект из кода. Требуется Label имя, указанное атрибутом x:Name .

<Label x:Name="valueLabel"
       Text="A simple Label"
       Font="Large"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />

Префикс x атрибута x:Name указывает, что этот атрибут является встроенным в XAML.

Имя атрибута x:Name имеет те же правила, что и имена переменных C#. Например, он должен начинаться с буквы или подчеркивания и содержать не внедренные пробелы.

ValueChanged Теперь обработчик событий может задать Label новое Slider значение. Новое значение доступно из аргументов событий:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

Или обработчик может получить Slider объект, создающий это событие из аргумента sender , и получить Value свойство из этого:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

При первом запуске программы значение не отображаетсяSlider, Label так как ValueChanged событие еще не запущено. Но любая манипуляция Slider приводит к отображению значения:

Slider Value Displayed

Теперь для Button. Давайте имитируем ответ на Clicked событие, отображая оповещение с Text кнопкой. Обработчик событий может безопасно привести аргумент к аргументу senderButton , а затем получить доступ к его свойствам:

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!",
        "The button labeled '" + button.Text + "' has been clicked",
        "OK");
}

Метод определяется так async , как DisplayAlert метод является асинхронным и должен быть предопределен оператором await , который возвращается после завершения метода. Так как этот метод получает Button событие из аргумента sender , один и тот же обработчик может использоваться для нескольких кнопок.

Вы видели, что объект, определенный в XAML, может запустить событие, которое обрабатывается в файле кода программной части, и что файл программной части может получить доступ к объекту, определенному в XAML, с помощью имени, назначенного ему атрибутом x:Name . Это два основных способа взаимодействия кода и XAML.

Дополнительные сведения о том, как работает XAML, изучите только что созданный файл XamlPlusCode.xaml.g.cs, который теперь включает любое имя, назначенное любому x:Name атрибуту в качестве частного поля. Ниже приведена упрощенная версия этого файла:

public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

    private void InitializeComponent() {
        this.LoadFromXaml(typeof(XamlPlusCodePage));
        valueLabel = this.FindByName<Label>("valueLabel");
    }
}

Объявление этого поля позволяет переменной свободно использовать в любом месте в файле частичного XamlPlusCodePage класса под вашей юрисдикцией. Во время выполнения поле назначается после синтаксического анализа XAML. Это означает, что valueLabel поле начинается null , XamlPlusCodePage но допустимо после InitializeComponent вызова конструктора.

После InitializeComponent возврата элемента управления обратно в конструктор визуальные элементы страницы были созданы так же, как если бы они были экземплярированы и инициализированы в коде. XAML-файл больше не играет никакой роли в классе. Эти объекты можно управлять на странице любым способом, например, путем добавления представлений в StackLayoutстраницу или настройки Content свойства страницы на что-то другое. Вы можете "ходить по дереву", проверив Content свойство страницы и элементы в Children коллекциях макетов. Можно задать свойства для представлений, доступных таким образом, или динамически назначать обработчикам событий.

Почувствуйте себя бесплатно. Это ваша страница, а XAML — это только средство для создания его содержимого.

Итоги

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