共用方式為


第 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 專案表示的物件。
  • TextVerticalOptionsFontAttributesFontSize 屬性屬性。 Xamarin.Forms它們是以 XML 屬性表示的屬性。
  • 在該最後的代碼段中, TextColor 已成為 屬性專案。 它是屬性 Xamarin.Forms ,但現在是 XML 元素。

屬性元素的定義一開始似乎是違反 XML 語法,但不是。 句點在 XML 中沒有特殊意義。 對 XML 譯碼器來說, Label.TextColor 只是一般的子專案。

不過,在 XAML 中,此語法非常特殊。 屬性元素的其中一個規則是標記中 Label.TextColor 沒有其他規則。 屬性的值一律定義為屬性專案開始和結束標記之間的內容。

您可以在多個屬性上使用 property-element 語法:

<Label Text="Hello, XAML!"
       VerticalOptions="Center">
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>

或者,您可以針對所有屬性使用 property-element 語法:

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

一開始,屬性元素語法看起來似乎是相當簡單的專案不必要的長風取代專案,在這些範例中,這當然是這樣。

不過,當屬性的值太複雜而無法表示為簡單字串時,property-element 語法就變得很重要。 在 property-element 標記中,您可以具現化另一個物件並設定其屬性。 例如,您可以明確地將 屬性設定為LayoutOptions具有屬性VerticalOptions設定的值:

<Label>
    ...
    <Label.VerticalOptions>
        <LayoutOptions Alignment="Center" />
    </Label.VerticalOptions>
</Label>

另一個範例:有Grid兩個名為 和ColumnDefinitions的屬性RowDefinitions。 這兩個屬性的類型為 RowDefinitionCollectionColumnDefinitionCollection,這些是 和 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 ,需要 和 ColumnDefinitions 集合的屬性元素RowDefinitions來定義資料列和數據行。 不過,程式設計人員也必須有某種方式來指出每個子系 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.Row 0 的 和 Grid.Column 設定並非必要,但一般會納入以明確性為目的。

以下是其外觀:

方格版面配置

從語法來看,這些 、、 和屬性似乎都是 靜態欄位或屬性Grid,但有趣的是,Grid不會定義名為、ColumnRowSpanColumnSpan的任何名稱RowGrid.ColumnSpanGrid.RowSpanGrid.ColumnGrid.Row

Grid而是定義四個名為 RowProperty、、 ColumnPropertyRowSpanPropertyColumnSpanProperty的可系結屬性。 這些是稱為附加屬性的特殊可系結屬性類型。 它們是由 類別所定義, Grid 但在的 Grid子系上設定。

當您想要在程式代碼中使用這些附加屬性時,類別 Grid 會提供名為 SetRowGetColumn等的靜態方法。 但在 XAML 中,這些附加屬性會設定為使用簡單屬性名稱之 Grid 子系中的屬性。

附加屬性一律可在 XAML 檔案中辨識為同時包含類別和屬性名稱的屬性,並以句點分隔。 它們稱為 附加屬性 ,因為它們是由一個類別所定義, Grid但附加至其他物件(在此案例中為的子系 Grid)。 在配置期間, Grid 可以詢問這些附加屬性的值,以瞭解放置每個子系的位置。

類別 AbsoluteLayout 會定義兩個名為 LayoutBoundsLayoutFlags的附加屬性。 以下是使用 比例定位和重設大小功能 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,、 GridAbsoluteLayout 物件會設定為 ContentContentPage屬性,而這些配置子系實際上是集合中的 Children 專案。 然而,這些 ContentChildren 屬性在 XAML 檔案中無處可去。

您當然可以包含 ContentChildren 屬性作為屬性元素,例如在 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 加上一個屬性旗標。 如果您在線上Xamarin.Forms檔案中查閱 類別ContentPage,您會看到此屬性:

[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage

這表示 Content 不需要 property-element 標記。 假設在開始和結束 ContentPage 卷標之間出現的任何 XML 內容都會指派給 Content 屬性。

StackLayoutGridAbsoluteLayoutRelativeLayout 全都衍生自 Layout<View>,而且如果您在檔中查閱Layout<T>Xamarin.Forms,您會看到另一個ContentProperty屬性:

[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...

這可讓版面配置的內容自動新增至集合, Children 而不需要明確的 Children 屬性元素標記。

其他類別也有 ContentProperty 屬性定義。 例如,的內容屬性 LabelText。 檢查 API 檔以取得其他人。

使用 OnPlatform 的平台差異

在單頁應用程式中,通常會在頁面上設定 Padding 屬性,以避免覆寫 iOS 狀態列。 在程式代碼中 Device.RuntimePlatform ,您可以針對此目的使用 屬性:

if (Device.RuntimePlatform == Device.iOS)
{
    Padding = new Thickness(0, 20, 0, 0);
}

您也可以使用 OnPlatformOn 類別,在 XAML 中執行類似動作。 第一個包含靠近頁面頂端之屬性的屬性元素 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>

在這些標籤內,包含標籤 OnPlatformOnPlatform 是泛型類別。 在此情況下,您必須指定泛型型別自變數, 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>

此標記可以簡化。 的內容屬性 OnPlatformPlatforms,因此可以移除這些屬性元素標記:

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

這是在 XAML 中設定平臺相依 Padding 屬性的標準方式。 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 中用來自定義每個平臺的 UI 外觀。 它提供與 OnPlatformOn 類別相同的功能,但具有更簡潔的表示法。 如需詳細資訊,請參閱 OnPlatform 標記延伸

摘要

使用屬性元素和附加屬性,已建立大部分的基本 XAML 語法。 不過,有時候您需要以間接方式將屬性設定為物件,例如,從資源字典。 下一部分第3部分 涵蓋此方法。XAML 標記延伸