Part 2 (Развертывание виртуальных машин в облаке, часть 2). Основной синтаксис XAML
XAML в основном предназначен для создания экземпляров и инициализации объектов. Но часто свойства должны быть заданы для сложных объектов, которые не могут быть легко представлены как XML-строки, а иногда свойства, определенные одним классом, должны быть заданы в дочернем классе. Для этих двух потребностей требуются основные функции синтаксиса XAML элементов свойств и присоединенных свойств.
Элементы свойства
В XAML свойства классов обычно задаются как XML-атрибуты:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large"
TextColor="Aqua" />
Однако существует альтернативный способ задания свойства в XAML. Чтобы попробовать эту альтернативу TextColor
, сначала удалите существующий TextColor
параметр:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />
Откройте тег пустого элемента Label
, разделив его на начальные и конечные теги:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
</Label>
В этих тегах добавьте начальные и конечные теги, состоящие из имени класса и имени свойства, разделенного точкой:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
</Label.TextColor>
</Label>
Задайте значение свойства в качестве содержимого этих новых тегов, как показано ниже.
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Эти два способа указать TextColor
свойство функционально эквивалентны, но не используйте два способа для одного и того же свойства, так как это будет эффективно задавать свойство дважды и может быть неоднозначным.
С помощью этого нового синтаксиса можно ввести некоторые удобные термины:
Label
— это элемент объекта. Это объект, выраженный Xamarin.Forms как XML-элемент.Text
,VerticalOptions
иFontSize
являются атрибутами свойств.FontAttributes
Они являются свойствами, выраженными Xamarin.Forms как XML-атрибуты.- В этом последнем фрагменте
TextColor
кода стал элементом свойства. Xamarin.Forms Это свойство, но теперь это XML-элемент.
Определение элементов свойств может сначала показаться нарушением синтаксиса XML, но это не так. Период не имеет особого значения в XML. Для декодера Label.TextColor
XML это просто обычный дочерний элемент.
Однако в XAML этот синтаксис очень особый. Одним из правил для элементов свойства является то, что в теге ничего другого Label.TextColor
не может отображаться. Значение свойства всегда определяется как содержимое между начальными и конечными тегами элемента свойства.
Синтаксис элемента свойства можно использовать для нескольких свойств:
<Label Text="Hello, XAML!"
VerticalOptions="Center">
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Или можно использовать синтаксис элемента свойства для всех свойств:
<Label>
<Label.Text>
Hello, XAML!
</Label.Text>
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
<Label.VerticalOptions>
Center
</Label.VerticalOptions>
</Label>
Во-первых, синтаксис элемента свойства может показаться ненужным длинным заменой для чего-то сравнительно простого, и в этих примерах, безусловно, это так.
Однако синтаксис элемента свойства становится важным, если значение свойства слишком сложно, чтобы быть выражено как простая строка. В тегах элемента свойства можно создать экземпляр другого объекта и задать его свойства. Например, можно явно задать свойство, например VerticalOptions
LayoutOptions
значение с параметрами свойств:
<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>
Другой пример: Grid
у него есть два свойства с именем RowDefinitions
и ColumnDefinitions
. Эти два свойства имеют тип RowDefinitionCollection
и ColumnDefinitionCollection
являются коллекциями и ColumnDefinition
объектамиRowDefinition
. Для задания этих коллекций необходимо использовать синтаксис элемента свойства.
Вот начало XAML-файла для класса, в котором показаны теги элементов свойства для GridDemoPage
коллекций и ColumnDefinitions
коллекцийRowDefinitions
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
...
</Grid>
</ContentPage>
Обратите внимание, что сокращенный синтаксис определяет ячейки автомасштабирования, ячейки ширины пикселей и высоты, а также параметры звезды.
Присоединенные свойства
Вы только что видели, что Grid
необходимы элементы свойств для RowDefinitions
коллекций и ColumnDefinitions
строк для определения строк и столбцов. Однако для программиста также должен быть какой-то способ указать строку и столбец, где находится каждый дочерний элемент Grid
.
В теге для каждого дочернего Grid
элемента указывается строка и столбец этого дочернего элемента, используя следующие атрибуты:
Grid.Row
Grid.Column
Значения по умолчанию этих атрибутов — 0. Можно также указать, охватывает ли дочерний элемент несколько строк или столбцов с этими атрибутами:
Grid.RowSpan
Grid.ColumnSpan
Эти два атрибута имеют значения по умолчанию 1.
Ниже приведен полный файл GridDemoPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="Autosized cell"
Grid.Row="0" Grid.Column="0"
TextColor="White"
BackgroundColor="Blue" />
<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />
<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />
<Label Text="Leftover space"
Grid.Row="1" Grid.Column="1"
TextColor="Purple"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two rows (or more if you want)"
Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
TextColor="Yellow"
BackgroundColor="Blue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two columns"
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
TextColor="Blue"
BackgroundColor="Yellow"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Fixed 100x100"
Grid.Row="2" Grid.Column="2"
TextColor="Aqua"
BackgroundColor="Red"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</Grid>
</ContentPage>
Grid.Column
Параметры Grid.Row
0 не требуются, но обычно включаются в целях ясности.
Вот как выглядит:
Судя по синтаксису, эти Grid.Row
Grid.RowSpan
Grid.Column
, и Grid.ColumnSpan
атрибуты, как представляется, статические поля или свойстваGrid
, но интересно, Grid
не определяет ничего именованногоRow
, Column
RowSpan
или.ColumnSpan
Вместо этого Grid
определяет четыре привязываемых свойства с именем RowProperty
, , ColumnProperty
RowSpanProperty
и ColumnSpanProperty
. Это специальные типы привязываемых свойств, известных как присоединенные свойства. Они определяются классом Grid
, но задаются на дочерних элементах Grid
.
Если вы хотите использовать эти присоединенные свойства в коде Grid
, класс предоставляет статические методы с именем SetRow
, GetColumn
и т. д. Но в XAML эти присоединенные свойства задаются в качестве атрибутов в дочерних элементах с помощью простых Grid
имен свойств.
Присоединенные свойства всегда распознаются в XAML-файлах как атрибуты, содержащие как класс, так и имя свойства, разделенное точкой. Они называются присоединенными свойствами , так как они определяются одним классом (в данном случае Grid
), но присоединены к другим объектам (в данном случае дочерние Grid
объекты). Во время макета можно провести допрос значений этих присоединенных свойств, Grid
чтобы узнать, где разместить каждый дочерний элемент.
Класс AbsoluteLayout
определяет два присоединенных свойства с именем LayoutBounds
и LayoutFlags
. Ниже приведен шаблон проверки доски, реализованный с помощью пропорциональной позиции и функций AbsoluteLayout
изменения размера:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.AbsoluteDemoPage"
Title="Absolute Demo Page">
<AbsoluteLayout BackgroundColor="#FF8080">
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
</ContentPage>
Результат будет таким:
Для чего-то подобного вы можете задать вопрос о том, как использовать XAML. Конечно, повторение и регулярность LayoutBounds
прямоугольника предполагает, что это может быть лучше реализовано в коде.
Это, безусловно, законная проблема, и нет проблем с балансировкой использования кода и разметки при определении пользовательских интерфейсов. Легко определить некоторые визуальные элементы в XAML, а затем использовать конструктор файла кода для добавления дополнительных визуальных элементов, которые могут быть лучше сформированы в циклах.
Свойства содержимого
В предыдущих примерах StackLayout
Grid
для объектов и AbsoluteLayout
объектов задано Content
свойство ContentPage
объекта, а дочерние элементы этих макетов фактически являются элементами коллекцииChildren
. Тем не менее, эти Content
свойства Children
нигде не находятся в XAML-файле.
Вы, безусловно, можете включить Content
и Children
свойства в качестве элементов свойств, например в примере XamlPlusCode :
<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">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="valueLabel"
Text="A simple Label"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Реальный вопрос: Почему эти элементы свойств не требуются в XAML-файле?
Элементы, определенные Xamarin.Forms для использования в XAML, могут иметь одно свойство, помеченное в атрибуте ContentProperty
класса. Если вы ищете ContentPage
класс в онлайн-документации Xamarin.Forms , вы увидите этот атрибут:
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
Это означает, что Content
теги элементов свойства не требуются. Предполагается, что любой XML-контент, отображаемый между тегами начала и конца ContentPage
, назначается свойству Content
.
StackLayout
, Grid
, AbsoluteLayout
и все производные от Layout<View>
, и RelativeLayout
если вы ищете Layout<T>
в Xamarin.Forms документации, вы увидите другой ContentProperty
атрибут:
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
Это позволяет автоматически добавлять содержимое макета в Children
коллекцию без явных Children
тегов элементов свойств.
Другие классы также имеют ContentProperty
определения атрибутов. Например, свойство содержимого Label
имеет значение Text
. Ознакомьтесь с документацией по API для других пользователей.
Различия платформ с OnPlatform
В одностраничных приложениях обычно устанавливается Padding
свойство на странице, чтобы избежать перезаписи строки состояния iOS. В коде Device.RuntimePlatform
для этой цели можно использовать свойство:
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}
Вы также можете сделать что-то подобное в XAML с помощью OnPlatform
и On
классов. Сначала включите элементы свойств для Padding
свойства в верхней части страницы:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
</ContentPage.Padding>
...
</ContentPage>
В этих тегах включите OnPlatform
тег. OnPlatform
— универсальный класс. В этом случае Thickness
необходимо указать аргумент универсального типа, который является типом Padding
свойства. К счастью, есть атрибут XAML специально для определения универсальных аргументов x:TypeArguments
. Это должно соответствовать типу свойства, которое вы задаете:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
OnPlatform
имеет свойство с именем Platforms
, которое является IList
объектами On
. Используйте теги элементов свойства для этого свойства:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Теперь добавьте On
элементы. Для каждого задается Platform
свойство и Value
свойство для разметки Thickness
для свойства:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Эту разметку можно упростить. Свойство содержимого OnPlatform
имеет значение Platforms
, поэтому эти теги элементов свойств можно удалить:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Свойство Platform
On
типа IList<string>
, поэтому можно включить несколько платформ, если значения одинаковы:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android, UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Так как для Android и UWP задано значение Padding
по умолчанию, этот тег можно удалить:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Это стандартный способ задать свойство, зависимое от Padding
платформы, в XAML. Value
Если параметр не может быть представлен одной строкой, можно определить для него элементы свойств:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS">
<On.Value>
0, 20, 0, 0
</On.Value>
</On>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Примечание.
OnPlatform
Расширение разметки также можно использовать в XAML для настройки внешнего вида пользовательского интерфейса на основе платформы. Он предоставляет те же функции, что OnPlatform
и On
классы, но с более кратким представлением. Дополнительные сведения см. в разделе "Расширение разметки OnPlatform".
Итоги
С элементами свойств и присоединенными свойствами была создана большая часть базового синтаксиса XAML. Однако иногда необходимо задать свойства объектам косвенно, например из словаря ресурсов. Этот подход рассматривается в следующей части, часть 3. Расширения разметки XAML.