样式继承
Style的TargetType提供两种不同的功能:下一节隐式样式中描述了其中一种功能。 另一个函数是为了XAML解析器的好处。 XAML解析器必须能够解析Setter对象中的属性名称,并且为此需要TargetType提供的类名。
样式中的所有属性必须由Target?Type属性中指定的类定义或继承。 设置Style的可视元素的类型必须与TargetType或TargetType的派生类相同。
如果只需要为View定义的属性设置样式,则可以将TargetType设置为View,并仍然使用按钮上的样式或任何其他View派生,如在BasicStyle程序的此修改版本中:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicStyle.BasicStylePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="viewStyle" TargetType="View">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BackgroundColor" Value="Pink" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource viewStyle}" />
<Label Text ="A bit of text"
Style="{StaticResource viewStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource viewStyle}" />
<Label Text ="Another bit of text"
Style="{StaticResource viewStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource viewStyle}" />
</StackLayout>
</ContentPage>
如您所见,相同的样式应用于StackLayout的所有Button和Label子项:
但是假设你现在想要扩展这种风格,但对于Button和Label则不同。那可能吗?
是的。样式可以源自其他样式。 Style类包含一个名为BasedOn的属性Style。在代码中,您可以将此BasedOn属性直接设置为另一个Style对象。在XAML中,将BasedOn属性设置为引用先前创建的样式的StaticResource标记扩展。新样式可以包含新属性的Setter对象,或者使用它们覆盖早期样式中的属性。 BasedOn样式必须以新样式TargetType的相同类或祖先类为目标。
这是名为StyleInheritance的项目的XAML文件。该应用程序有两个目的引用Xamarin.FormsBook.Toolkit程序集:它使用HslColor标记扩展来证明标记扩展是Setter对象中的合法值设置,并且可以证明可以为自定义类定义样式,在这种情况下AltLabel。
ResourceDictionary包含四种样式:第一种具有“visualStyle”的字典键。带有“baseStyle”字典键的Style来自“visualStyle”。带有“la?belStyle”和“buttonStyle”键的样式来自“baseStyle”:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit=
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
x:Class="StyleInheritance.StyleInheritancePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="visualStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor"
Value="{toolkit:HslColor H=0, S=1, L=0.8}" />
</Style>
<Style x:Key="baseStyle" TargetType="View"
BasedOn="{StaticResource visualStyle}">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
<Style x:Key="labelStyle" TargetType="toolkit:AltLabel"
BasedOn="{StaticResource baseStyle}">
<Setter Property="TextColor" Value="Black" />
<Setter Property="PointSize" Value="12" />
</Style>
<Style x:Key="buttonStyle" TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="BorderWidth" Value="2" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Style>
<StaticResourceExtension Key="visualStyle" />
</ContentPage.Style>
<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource buttonStyle}" />
<toolkit:AltLabel Text ="A bit of text"
Style="{StaticResource labelStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource buttonStyle}" />
<toolkit:AltLabel Text ="Another bit of text"
Style="{StaticResource labelStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage>
在参考资源部分之后,立即将页面本身的Style属性设置为“visualStyle”样式:
<ContentPage.Style>
<StaticResourceExtension Key="visualStyle" />
</ContentPage.Style>
因为Page派生自VisualElement而不是View,所以这是可以应用于页面的资源词典中的唯一样式。 但是,在Re?sources部分之后才能将样式应用于页面,因此使用StaticResource的元素形式是一个很好的解决方案。 页面的整个背景基于此样式着色,并且样式也由所有其他样式继承:
如果AltLabel的样式仅包含Label定义的属性的Setter对象,则TargetType可以是Label而不是AltLabel。但Style具有PointSize属性的Setter。该属性由AltLabel定义,因此TargetType必须是toolkit:AltLabel。
可以为PointSize属性定义Setter,因为PointSize由可绑定属性支持。如果将AltLabel中BindableProperty对象的可访问性从公共更改为私有,则该属性仍可用于AltLabel的许多常规用法,但现在PointSize可以不在样式Setter中设置。 XAML解析器会抱怨它无法找到PointSizeProperty,它是支持PointSize属性的可绑定属性。
您在第10章中发现了StaticResource的工作原理:当XAML解析器遇到StaticResource标记扩展时,它会在可视化树中搜索匹配的字典键。这个过程对风格有影响。您可以在一个“资源”部分中定义样式,然后使用可视树中较低的“资源”部分中具有相同字典键的另一个样式覆盖该样式。将BasedOn属性设置为StaticResource标记扩展时,必须在相同的Resources部分(如StyleInheritance程序中演示)或可视树中较高的Resources部分中定义您派生的样式。
这意味着您可以使用两种分层方式在XAML中构建样式:您可以使用BasedOn从其他样式派生样式,并且可以在可视树中的不同级别定义样式,这些样式派生自可视树中较高的样式或替换它们完全。
对于具有多个页面和大量标记的大型应用程序,定义样式的建议非常简单 - 将样式定义为尽可能接近使用这些样式的元素。
遵循此建议有助于维护程序,并在使用隐式样式时变得特别重要。