Часть 1. Начало работы с XAML
Xamarin.Forms В приложении XAML в основном используется для определения визуального содержимого страницы и работает вместе с файлом кода C#.
Файл программной части предоставляет поддержку кода для разметки. Вместе эти два файла вносят вклад в новое определение класса, включающее дочерние представления и инициализацию свойств. В XAML-файле классы и свойства ссылаются на XML-элементы и атрибуты, а также устанавливаются связи между разметкой и кодом.
Создание решения
Чтобы начать редактирование первого XAML-файла, используйте Visual Studio или Visual Studio для Mac для создания нового Xamarin.Forms решения. (Выберите вкладку ниже, соответствующую вашей среде.)
В Windows запустите Visual Studio 2019 и в окне запуска нажмите кнопку "Создать проект", чтобы создать новый проект :
В окне Создать проект в раскрывающемся списке Тип проекта выберите Мобильное приложение, а затем выберите шаблон Мобильное приложение (Xamarin.Forms) и нажмите кнопку Далее:
В окне "Настройка нового проекта" задайте имя проекта в XamlSamples (или любой другой вариант) и нажмите кнопку "Создать".
В диалоговом окне "Новое кроссплатформенное приложение" нажмите кнопку "Пустой" и нажмите кнопку "ОК":
В решении создаются четыре проекта: библиотека 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" означает созданный. Это другое определение частичного MainPage
InitializeComponent
класса, содержащее определение метода, вызываемого конструктором MainPage
. Затем эти два определения частичного MainPage
класса можно скомпилировать вместе. В зависимости от того, компилируется ли XAML-файл или двоичный формат XAML-файла, внедряется в исполняемый файл.
Во время выполнения код в конкретном проекте платформы вызывает LoadApplication
метод, передавая в него новый экземпляр App
класса в библиотеке .NET Standard. Конструктор App
классов создает экземпляры MainPage
. Конструктор этого класса InitializeComponent
вызывает метод, который затем вызывает LoadFromXaml
метод, который извлекает XAML-файл (или его скомпилированный двоичный файл) из библиотеки .NET Standard. LoadFromXaml
Инициализирует все объекты, определенные в XAML-файле, подключает их все вместе в отношениях родительского дочернего элемента, присоединяет обработчики событий, определенные в коде, к событиям, заданным в XAML-файле, и задает результирующий дерево объектов в качестве содержимого страницы.
Хотя обычно вам не нужно тратить много времени на созданные файлы кода, иногда исключения среды выполнения создаются в коде в созданных файлах, поэтому их следует ознакомиться с ними.
При компиляции и запуске этой программы Label
элемент отображается в центре страницы, как предполагает XAML:
Для более интересных визуальных элементов все, что вам нужно, является более интересным XAML.
Добавление новых страниц XAML
Чтобы добавить в проект другие классы на основе ContentPage
XAML, выберите проект библиотеки XamlSamples .NET Standard, щелкните правой кнопкой мыши и выберите команду "Добавить > новый элемент...". В диалоговом окне "Добавление нового элемента" выберите страницу содержимого элементов Visual C# >>Xamarin.Forms(не страницу содержимого (C#), которая создает страницу только для кода или представление содержимого, которое не является страницей. Укажите имя страницы, например HelloXamlPage:
В проект добавляются два файла 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-элемента. Свойства этого класса, включая Title
ContentPage
и семь свойств Label
, обычно отображаются как XML-атрибуты.
Для задания значений этих свойств существует множество сочетаний клавиш. Некоторые свойства являются базовыми типами данных: например, Title
свойства имеют типDouble
String
, Rotation
тип и IsVisible
(который true
по умолчанию и задан здесь только для иллюстрации) имеет типBoolean
.Text
Свойство HorizontalTextAlignment
имеет тип TextAlignment
, который является перечислением. Для свойства любого типа перечисления необходимо указать имя члена.
Однако для свойств более сложных типов преобразователи используются для анализа XAML. Это классы, Xamarin.Forms производные от TypeConverter
. Многие из них являются общедоступными классами, но некоторые из них не являются. Для этого конкретного XAML-файла некоторые из этих классов играют роль за кулисами:
LayoutOptionsConverter
VerticalOptions
для свойстваFontSizeConverter
FontSize
для свойстваColorTypeConverter
TextColor
для свойства
Эти преобразователи управляют допустимым синтаксисом параметров свойств.
Может 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
. Ниже приведена результирующая страница на iPhone, Android и UWP:
Вы можете вернуться к MainPage
кнопке < "Назад " в iOS, используя стрелку влево в верхней части страницы или в нижней части телефона в Android или с помощью стрелки влево в верхней части страницы в Windows 10.
Вы можете поэкспериментировать с XAML для различных способов отрисовки Label
. Если необходимо внедрить любые символы Юникода в текст, можно использовать стандартный синтаксис XML. Например, чтобы поместить приветствие в смарт-кавычки, используйте следующую команду:
<Label Text="“Hello, XAML!”" … />
Вот как выглядит:
Взаимодействие XAML и кода
Пример HelloXamlPage содержит только один на Label
странице, но это очень необычно. Большинство ContentPage
производных задают Content
свойство макету определенного типа, например StackLayout
. Свойство Children
StackLayout
определяется 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-файл синтаксически завершен и выглядит следующим образом:
Однако, скорее всего, вы считаете, что эта программа будет функционально недостаточной. 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
приводит к отображению значения:
Теперь для Button
. Давайте имитируем ответ на Clicked
событие, отображая оповещение с Text
кнопкой. Обработчик событий может безопасно привести аргумент к аргументу sender
Button
, а затем получить доступ к его свойствам:
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.