Part 2 (Развертывание виртуальных машин в облаке, часть 2). Основной синтаксис XAML

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

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>

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

Однако синтаксис элемента свойства становится важным, если значение свойства слишком сложно, чтобы быть выражено как простая строка. В тегах элемента свойства можно создать экземпляр другого объекта и задать его свойства. Например, можно явно задать свойство, например VerticalOptionsLayoutOptions значение с параметрами свойств:

<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 Layout

Судя по синтаксису, эти Grid.RowGrid.RowSpanGrid.Column, и Grid.ColumnSpan атрибуты, как представляется, статические поля или свойстваGrid, но интересно, Grid не определяет ничего именованногоRow, ColumnRowSpanили.ColumnSpan

Вместо этого Grid определяет четыре привязываемых свойства с именем RowProperty, , ColumnPropertyRowSpanPropertyи ColumnSpanProperty. Это специальные типы привязываемых свойств, известных как присоединенные свойства. Они определяются классом Grid , но задаются на дочерних элементах Grid.

Если вы хотите использовать эти присоединенные свойства в коде Grid , класс предоставляет статические методы с именем SetRow, GetColumnи т. д. Но в XAML эти присоединенные свойства задаются в качестве атрибутов в дочерних элементах с помощью простых Grid имен свойств.

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

Класс AbsoluteLayout определяет два присоединенных свойства с именем LayoutBounds и LayoutFlags. Ниже приведен шаблон проверка board, реализованный с помощью пропорциональной позиции и функций 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>

Результат будет таким:

Absolute Layout

Для чего-то подобного вы можете задать вопрос о том, как использовать XAML. Конечно, повторение и регулярность LayoutBounds прямоугольника предполагает, что это может быть лучше реализовано в коде.

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

Свойства содержимого

В предыдущих примерах StackLayoutGridдля объектов и 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>

Свойство PlatformOn типа 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.