资源词典
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章中探讨。