第 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
FontAttributes
和FontSize
屬性屬性。 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
。 這兩個屬性的類型為 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
,需要 和 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
不會定義名為、Column
、 RowSpan
或ColumnSpan
的任何名稱Row
。Grid.ColumnSpan
Grid.RowSpan
Grid.Column
Grid.Row
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
加上一個屬性旗標。 如果您在線上Xamarin.Forms檔案中查閱 類別ContentPage
,您會看到此屬性:
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
這表示 Content
不需要 property-element 標記。 假設在開始和結束 ContentPage
卷標之間出現的任何 XML 內容都會指派給 Content
屬性。
StackLayout
、Grid
、 AbsoluteLayout
和 RelativeLayout
全都衍生自 Layout<View>
,而且如果您在檔中查閱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);
}
您也可以使用 OnPlatform
和 On
類別,在 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>
在這些標籤內,包含標籤 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>
這是在 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 外觀。 它提供與 OnPlatform
和 On
類別相同的功能,但具有更簡潔的表示法。 如需詳細資訊,請參閱 OnPlatform 標記延伸。
摘要
使用屬性元素和附加屬性,已建立大部分的基本 XAML 語法。 不過,有時候您需要以間接方式將屬性設定為物件,例如,從資源字典。 下一部分第3部分 涵蓋此方法。XAML 標記延伸。