資源詞典
Xamarin.Forms還支援第二種共享對象和值的方法,雖然這種方法比x:靜态标記擴充稍微有點開銷,但它更通用 - 因為所有東西 - 共享對象和使用的可視元素 它們 - 可以用XAML表示。
VisualElement定義了一個名為Resources的屬性,它屬于ResourceDictionary類型 - 一個帶有字元串鍵和類型為object的值的字典。 可以在XAML中将項添加到此詞典中,并且可以使用StaticResource和DynamicResource标記擴充在XAML中通路它們。
雖然x:Static和StaticResource有一些相似的名稱,但它們完全不同:x:Static引用常量,靜态字段,靜态屬性或枚舉成員,而StaticResource從ResourceDictionary檢索對象。
雖然x:Static标記擴充是XAML固有的(是以出現在帶有x字首的XAML中),但StaticResource和DynamicResource标記擴充不是。 它們是Windows Presentation Foundation中原始XAML實作的一部分,Silverlight,Windows Phone 7和8以及Windows 8和10也支援StaticResource。
你将使用StaticResource用于大多數目的,并為一些特殊的應用程式保留DynamicResource,是以讓我們從StaticResource開始。
StaticResource用于大多數目的
假設您已在StackLayout中定義了三個按鈕:
<StackLayout>
<Button Text=" Carpe diem "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
<Button Text=" Sapere aude "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
<Button Text=" Discere faciendo "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
</StackLayout>
當然,這有點不切實際。 沒有為這些按鈕設定Clicked事件,并且通常按鈕文本不是拉丁文。 但這是他們的樣子:

除文本外,所有三個按鈕都具有相同的屬性設定為相同的值。 像這樣的重複标記往往會錯誤地影響程式員。 這是對眼睛的冒犯,難以維持和改變。
最終你會看到如何使用樣式來真正減少重複标記。 現在,怎麼樣?目标不是縮短标記,而是将值合并到一個地方,這樣如果你想将TextColor屬性從Red更改為Blue,你可以用一次編輯而不是三次編輯。
顯然,您可以通過在代碼中定義值來為此作業使用x:Static。 但是,讓我們通過将值存儲在資源字典中來完成XAML中的所有操作。 從VisualEle?衍生的每個類都有一個ResourceDictionary類型的Resources屬性。 整個頁面中使用的資源通常存儲在ContentPage的Resources集合中。
第一步是将ContentPage的Resources屬性表示為屬性元素:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceSharing.ResourceSharingPage">
<ContentPage.Resources>
</ContentPage.Resources>
</ContentPage>
如果您還使用property-element标記在頁面上定義Padding屬性,則順序無關緊要。
出于性能目的,預設情況下Resources屬性為null,是以您需要顯式執行個體化ResourceDictionary:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceSharing.ResourceSharingPage">
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
在ResourceDictionary标記之間,您可以定義一個或多個對象或值。 必須使用您使用XAML x:Key屬性指定的字典鍵來辨別字典中的每個項目。 例如,下面是在字典中包含LayoutOptions值的文法,其中包含一個描述鍵,訓示此值是為設定水準選項定義的:
<LayoutOptions x:Key="horzOptions">Center</LayoutOptions>
因為這是一個LayoutOptions值,是以XAML解析器通路LayoutOptionsConverter類以轉換标記的内容,即文本“Center”。
在字典中存儲LayoutOptions值的第二種方法是讓XAML解析器執行個體化結構并從您指定的屬性設定LayoutOptions屬性:
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
BorderWidth屬性的類型為double,是以XAML 2009規範中定義的x:Double資料類型元素是理想的:
<x:Double x:Key="borderWidth">3</x:Double>
您可以将顔色值存儲在資源字典中,并将顔色的文本表示作為内容。 XAML解析器使用普通的ColorTypeConverter進行文本轉換:
<Color x:Key="textColor">Red</Color>
您還可以在哈希符号後面指定十六進制ARGB值。
您無法通過設定其R,G和B屬性來初始化Color值,因為這些屬性是get-only。 但是您可以使用x:Arguments或使用x:FactoryMethod和x:Arguments的Color工廠方法之一調用Color構造函數。
<Color x:Key="textColor"
x:FactoryMethod="FromHsla">
<x:Arguments>
<x:Double>0</x:Double>
<x:Double>1</x:Double>
<x:Double>0.5</x:Double>
<x:Double>1</x:Double>
</x:Arguments>
</Color>
注意x:Key和x:FactoryMethod屬性。
上面顯示的三個按鈕的BackgroundColor和BorderColor屬性設定為OnPlatform類的值。 幸運的是,您可以在字典中放置OnPlatform對象:
<OnPlatform x:Key="backgroundColor"
x:TypeArguments="Color"
Android="#404040" />
<OnPlatform x:Key="borderColor"
x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
注意x:Key和x:TypeArguments屬性。
FontSize屬性的字典項有些問題。 FontSize屬性的類型為double,是以如果您在字典中存儲實際的數值,那就沒問題了。 但是你不能在字典中存儲單詞“Large”,就好像它是雙重的一樣。 僅當“Large”字元串設定為FontSize屬性時,XAML解析器才使用FontSizeConverter。 是以,您需要将FontSize項存儲為字元串:
<x:String x:Key="fontSize">Large</x:String>
這是完整的字典:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceSharing.ResourceSharingPage">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions">Center</LayoutOptions>
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">3</x:Double>
<Color x:Key="textColor">Red</Color>
<OnPlatform x:Key="backgroundColor"
x:TypeArguments="Color"
Android="#404040" />
<OnPlatform x:Key="borderColor"
x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
<x:String x:Key="fontSize">Large</x:String>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
這有時被稱為頁面的資源部分。 在現實生活中,很多XAML檔案都以資源部分開頭。
您可以使用StaticResourceExtension支援的StaticResource标記擴充來引用字典中的項目。 該類定義了一個名為Key的屬性,您将其設定為字典鍵。 您可以将StaticResourceExtension用作property-element标記中的元素,也可以在花括号中使用StaticResourceExtension或StaticResource。 如果您使用的是大括号文法,則可以省略Key和等号,因為Key是StaticResourceExtension的content屬性。
ResourceSharing項目中的以下完整XAML檔案說明了以下三個選項:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceSharing.ResourceSharingPage">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions">Center</LayoutOptions>
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">3</x:Double>
<Color x:Key="textColor">Red</Color>
<OnPlatform x:Key="backgroundColor"
x:TypeArguments="Color"
Android="#404040" />
<OnPlatform x:Key="borderColor"
x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
<x:String x:Key="fontSize">Large</x:String>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text=" Carpe diem ">
<Button.HorizontalOptions>
<StaticResourceExtension Key="horzOptions" />
</Button.HorizontalOptions>
<Button.VerticalOptions>
<StaticResourceExtension Key="vertOptions" />
</Button.VerticalOptions>
<Button.BorderWidth>
<StaticResourceExtension Key="borderWidth" />
</Button.BorderWidth>
<Button.TextColor>
<StaticResourceExtension Key="textColor" />
</Button.TextColor>
<Button.BackgroundColor>
<StaticResourceExtension Key="backgroundColor" />
</Button.BackgroundColor>
<Button.BorderColor>
<StaticResourceExtension Key="borderColor" />
</Button.BorderColor>
<Button.FontSize>
<StaticResourceExtension Key="fontSize" />
</Button.FontSize>
</Button>
<Button Text=" Sapere aude "
HorizontalOptions="{StaticResource Key=horzOptions}"
VerticalOptions="{StaticResource Key=vertOptions}"
BorderWidth="{StaticResource Key=borderWidth}"
TextColor="{StaticResource Key=textColor}"
BackgroundColor="{StaticResource Key=backgroundColor}"
BorderColor="{StaticResource Key=borderColor}"
FontSize="{StaticResource Key=fontSize}" />
<Button Text=" Discere faciendo "
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
TextColor="{StaticResource textColor}"
BackgroundColor="{StaticResource backgroundColor}"
BorderColor="{StaticResource borderColor}"
FontSize="{StaticResource fontSize}" />
</StackLayout>
</ContentPage>
第三個按鈕中最簡單的文法是最常見的,實際上,文法是如此普遍,許多長期XAML開發人員可能完全不熟悉其他變體。 但是,如果您使用具有Key屬性的StaticResource版本,請不要在其上放置x字首。 x:Key屬性僅用于為ResourceDictionary中的項定義字典鍵。
字典中的對象和值在所有StaticResource引用之間共享。 在前面的例子中并不是那麼清楚,但要記住這一點。 例如,假設您将Button對象存儲在資源字典中:
<ContentPage.Resources>
<ResourceDictionary>
<Button x:Key="button"
Text="Shared Button?"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
</ResourceDictionary>
</ContentPage.Resources>
您當然可以通過使用StaticResourceExtension元素文法将Stack對象添加到StackLayout的Children集合中來在頁面上使用該Button對象:
<StackLayout>
<StaticResourceExtension Key="button" />
</StackLayout>
但是,為了将另一個副本放入StackLayout,您不能使用相同的字典項嗎?
<StackLayout>
<StaticResourceExtension Key="button" />
<StaticResourceExtension Key="button" />
</StackLayout>
那不行。 這兩個元素都引用相同的Button對象,并且特定的視覺元素隻能位于螢幕上的一個特定位置。 它不能在多個位置。
是以,視覺元素通常不存儲在資源字典中。 如果您需要在頁面上具有大部分相同屬性的多個元素,您将需要使用樣式,這将在第12章中探讨。