Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6658183
  • 博文数量: 915
  • 博客积分: 17977
  • 博客等级: 上将
  • 技术积分: 8846
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-26 09:59
个人简介

一个好老好老的老程序员了。

文章分类

全部博文(915)

文章存档

2022年(9)

2021年(13)

2020年(10)

2019年(40)

2018年(88)

2017年(130)

2015年(5)

2014年(12)

2013年(41)

2012年(36)

2011年(272)

2010年(1)

2009年(53)

2008年(65)

2007年(47)

2006年(81)

2005年(12)

分类: Android平台

2018-08-06 22:04:48

Xamarin.Forms应用程序通常包含具有相同属性设置的多个元素。例如,您可能有几个具有相同颜色,字体大小和布局选项的按钮。在代码中,您可以为循环中的多个按钮指定相同的属性,但在XAML中不能使用循环。如果您想避免大量重复标记,则需要另一种解决方案。
解决方案是Style类,它是在一个conient对象中合并的属性设置的集合。您可以将Style对象设置为从VisualElement派生的任何类的Style属性。通常,您将相同的Style对象应用于多个元素,并且样式在这些元素之间共享。
Style是在Xamarin.Forms应用程序中为视觉元素提供一致外观的主要工具。样式有助于减少XAML文件中的重复标记,并允许更轻松地更改和维护应用程序。
样式主要是考虑到XAML而设计的,它们可能不是在仅代码环境中发明的。但是,您将在本章中看到如何在代码中定义和使用样式,以及如何组合代码和标记以在运行时动态更改程序样式。

基本样式

在第10章“XAML标记扩展”中,您看到了三个包含大量相同标记的按钮。 他们又来了:


点击(此处)折叠或打开

  1. <StackLayout>
  2.     <Button Text=" Carpe diem "
  3.             HorizontalOptions="Center"
  4.             VerticalOptions="CenterAndExpand"
  5.             BorderWidth="3"
  6.             TextColor="Red"
  7.             FontSize="Large">
  8.         <Button.BackgroundColor>
  9.             <OnPlatform x:TypeArguments="Color"
  10.                         Android="#404040" />
  11.         </Button.BackgroundColor>
  12.         <Button.BorderColor>
  13.             <OnPlatform x:TypeArguments="Color"
  14.                         Android="White"
  15.                         WinPhone="Black" />
  16.         </Button.BorderColor>
  17.     </Button>
  18.     <Button Text=" Sapere aude "
  19.             HorizontalOptions="Center"
  20.             VerticalOptions="CenterAndExpand"
  21.             BorderWidth="3"
  22.             TextColor="Red"
  23.             FontSize="Large">
  24.         <Button.BackgroundColor>
  25.             <OnPlatform x:TypeArguments="Color"
  26.                         Android="#404040" />
  27.         </Button.BackgroundColor>
  28.         <Button.BorderColor>
  29.             <OnPlatform x:TypeArguments="Color"
  30.                         Android="White"
  31.                         WinPhone="Black" />
  32.         </Button.BorderColor>
  33.     </Button>
  34.     <Button Text=" Discere faciendo "
  35.             HorizontalOptions="Center"
  36.             VerticalOptions="CenterAndExpand"
  37.             BorderWidth="3"
  38.             TextColor="Red"
  39.             FontSize="Large">
  40.         <Button.BackgroundColor>
  41.             <OnPlatform x:TypeArguments="Color"
  42.                         Android="#404040" />
  43.         </Button.BackgroundColor>
  44.         <Button.BorderColor>
  45.             <OnPlatform x:TypeArguments="Color"
  46.                         Android="White"
  47.                         WinPhone="Black" />
  48.         </Button.BorderColor>
  49.     </Button>
  50. </StackLayout>

除Text属性外,所有三个按钮都具有相同的属性设置。
这个重复标记的一个部分解决方案涉及在资源分类中定义属性值并使用StaticResource标记扩展引用它们。 正如您在第10章的ResourceSharing项目中看到的,这种技术不会减少标记批量,但它确实在一个地方合并了值。
要减少标记批量,您需要一个样式。 Style对象几乎总是在ResourceDictionary中定义。 通常,您将从页面顶部的“资源”部分开始:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="BasicStyle.BasicStylePage">
  4.  
  5.     <ContentPage.Resources>
  6.         <ResourceDictionary>
  7.     ...
  8.         </ResourceDictionary>
  9.    </ContentPage.Resources>
  10.    ...
  11. </ContentPage>
使用单独的开始和结束标记实例化样式:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="BasicStyle.BasicStylePage">
  4.  
  5.     <ContentPage.Resources>
  6.         <ResourceDictionary>
  7.             <Style x:Key="buttonStyle" TargetType="Button">
  8.                 ...
  9.             </Style>
  10.         </ResourceDictionary>
  11.     </ContentPage.Resources>
  12.     ...
  13. </ContentPage>

因为Style是ResourceDictionary中的对象,所以您需要一个x:Key属性来为其提供描述性字典键。 您还必须设置TargetType属性。 这是样式设计的可视元素的类型,在本例中为Button。
正如您将在本章的下一部分中看到的那样,您还可以在代码中定义样式,在这种情况下,Style构造函数需要TargetType属性的Type类型的对象。 TargetType属性没有公共集访问器; 因此,在创建样式后无法更改TargetType属性。
Style还定义了另一个名为Setters的类型为IList 的重要get-only属性,它是Setter对象的集合。 每个Setter负责定义样式中的属性设置。 Setter类只定义了两个属性:

  • BindableProperty类型的属性
  • 对象类型的值
Style中设置的属性必须由可绑定属性支持! 但是,当您在XAML中设置Property属性时,请不要使用整个完全限定的可绑定属性名称。 只需指定文本名称,该名称与相关CLR属性的名称相同。 这是一个例子:

点击(此处)折叠或打开

  1. <Setter Property="HorizontalOptions" Value="Center" />
解析这些Setter实例的Value设置时,XAML解析器使用熟悉的TypeConverter类,因此您可以使用正常使用的相同属性设置。
Setters是Style的content属性,因此您不需要添加Style.Setters标记Setter对象的样式:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.                xmlns:x=""
  3.                x:Class="BasicStyle.BasicStylePage">
  4.  
  5.     <ContentPage.Resources>
  6.         <ResourceDictionary>
  7.             <Style x:Key="buttonStyle" TargetType="Button">
  8.             <Setter Property="HorizontalOptions" Value="Center" />
  9.             <Setter Property="VerticalOptions" Value="CenterAndExpand" />
  10.             <Setter Property="BorderWidth" Value="3" />
  11.             <Setter Property="TextColor" Value="Red" />
  12.             <Setter Property="FontSize" Value="Large" />
  13.             ...
  14.             </Style>
  15.         </ResourceDictionary>
  16.     </ContentPage.Resources>
  17.     ...
  18. </ContentPage>
BackgroundColor和BorderColor需要另外两个Setter对象。 这些涉及OnPlatform,起初似乎不可能在标记中表达。 但是,可以将Setter的Value属性表示为属性元素,并在属性元素标记之间使用OnPlatform标记:

点击(此处)折叠或打开

  1. <Setter Property="BackgroundColor">
  2.     <Setter.Value>
  3.         <OnPlatform x:TypeArguments="Color"
  4.                     Android="#404040" />
  5.     </Setter.Value>
  6. </Setter>
  7. <Setter Property="BorderColor">
  8.     <Setter.Value>
  9.         <OnPlatform x:TypeArguments="Color"
  10.                     Android="White"
  11.                     WinPhone="Black" />
  12.     </Setter.Value>
  13. </Setter>
最后一步是将此Style对象设置为每个Button的Style属性。 使用熟悉的StaticResource标记扩展来引用字典键。 这是BasicStyle项目中的完整XAML文件:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.                xmlns:x=""
  3.                x:Class="BasicStyle.BasicStylePage">
  4.  
  5.     <ContentPage.Resources>
  6.         <ResourceDictionary>
  7.             <Style x:Key="buttonStyle" TargetType="Button">
  8.                 <Setter Property="HorizontalOptions" Value="Center" />
  9.                 <Setter Property="VerticalOptions" Value="CenterAndExpand" />
  10.                 <Setter Property="BorderWidth" Value="3" />
  11.                 <Setter Property="TextColor" Value="Red" />
  12.                 <Setter Property="FontSize" Value="Large" />
  13.                 <Setter Property="BackgroundColor">
  14.                     <Setter.Value>
  15.                         <OnPlatform x:TypeArguments="Color"
  16.                                     Android="#404040" />
  17.                     </Setter.Value>
  18.                 </Setter>
  19.                 <Setter Property="BorderColor">
  20.                     <Setter.Value>
  21.                         <OnPlatform x:TypeArguments="Color"
  22.                                     Android="White"
  23.                                     WinPhone="Black" />
  24.                     </Setter.Value>
  25.                 </Setter>
  26.             </Style>
  27.         </ResourceDictionary>
  28.     </ContentPage.Resources>
  29.     <StackLayout>
  30.         <Button Text=" Carpe diem "
  31.                 Style="{StaticResource buttonStyle}" />
  32.  
  33.         <Button Text=" Sapere aude "
  34.                 Style="{StaticResource buttonStyle}" />
  35.  
  36.         <Button Text=" Discere faciendo "
  37.                 Style="{StaticResource buttonStyle}" />
  38.     </StackLayout>
  39. </ContentPage>
现在所有这些属性设置都在一个Style对象中,该对象在多个Button元素之间共享:
视觉效果与第10章中的ResourceSharing程序中的视觉效果相同,但标记更加简洁。
即使在使用标记中的Style对象之后,也很容易使用笨重的Value属性进行flummox。 假设您想使用Color.FromHsla静态方法为TextColor定义Setter。 您可以使用x:FactoryMethod attrib?ute定义这样的颜色,但是如何将这样一个难以置信的标记块设置为Setter对象的Value属性? 如前所述,解决方案几乎总是属性元素语法:

点击(此处)折叠或打开

  1. <ResourceDictionary>
  2.     <Style x:Key="buttonStyle" TargetType="Button">
  3.         ...
  4.         <Setter Property="TextColor">
  5.             <Setter.Value>
  6.                 <Color x:FactoryMethod="FromHsla">
  7.                     <x:Arguments>
  8.                         <x:Double>0.83</x:Double>
  9.                         <x:Double>1</x:Double>
  10.                         <x:Double>0.75</x:Double>
  11.                         <x:Double>1</x:Double>
  12.                     </x:Arguments>
  13.                  </Color>
  14.             </Setter.Value>
  15.         </Setter>
  16.         ...
  17.     </Style>
  18. </ResourceDictionary>
这是另一种方法:将Color值定义为资源字典中的单独项,然后使用StaticResource将其设置为Setter的Value属性:

点击(此处)折叠或打开

  1. <ResourceDictionary>
  2.     <Color x:Key="btnTextColor"
  3.            x:FactoryMethod="FromHsla">
  4.         <x:Arguments>
  5.             <x:Double>0.83</x:Double>
  6.             <x:Double>1</x:Double>
  7.             <x:Double>0.75</x:Double>
  8.             <x:Double>1</x:Double>
  9.         </x:Arguments>
  10.     </Color>
  11.  
  12.     <Style x:Key="buttonStyle" TargetType="Button">
  13.     ...
  14.         <Setter Property="TextColor" Value="{StaticResource btnTextColor}" />
  15.     ...
  16.     </Style>
  17. </ResourceDictionary>
如果您在多个样式或多个setter之间共享相同的Color值,这是一个很好的技术。
您可以通过直接在视觉元素中设置属性来覆盖样式中的属性设置。 请注意,第二个Button的TextColor属性设置为Maroon:

点击(此处)折叠或打开

  1. <StackLayout>
  2.     <Button Text=" Carpe diem "
  3.             Style="{StaticResource buttonStyle}" />
  4.  
  5.     <Button Text=" Sapere aude "
  6.             TextColor="Maroon"
  7.             Style="{StaticResource buttonStyle}" />
  8.  
  9.     <Button Text=" Discere faciendo "
  10.             Style="{StaticResource buttonStyle}" />
  11. </StackLayout>
中心按钮将具有栗色文本,而其他两个按钮将从样式中获取其TextColor设置。 直接在视觉元素上设置的属性有时称为本地设置或手动设置,它始终覆盖样式中的属性设置。
BasicStyle程序中的Style对象在三个按钮之间共享。 样式的共享对Setter对象具有重要意义。 设置为Setter的Value属性的任何对象都必须是可共享的。 不要试图做这样的事情:

点击(此处)折叠或打开

  1. <!-- Invalid XAML! -->
  2. <Style x:Key="frameStyle" TargetType="Frame">
  3.     <Setter Property="OutlineColor" Value="Accent" />
  4.     <Setter Property="Content">
  5.         <Setter.Value>
  6.             <Label Text="Text in a Frame" />
  7.         </Setter.Value>
  8.     </Setter>
  9. </Style>
此XAML不起作用有两个原因:内容不受BindableProperty支持,因此不能在Setter中使用。但是这里显而易见的意图是每个Frame-或至少应用此样式的每个Frame--将相同的Label对象作为内容获取。单个Label对象不能出现在页面上的多个位置。执行此类操作的更好方法是从Frame派生类并将Label设置为Content属性,或从ContentView派生包含Frame和Label的类。
您可能希望使用样式为Clicked等事件设置事件处理程序。这将是有用和方便的,但它不受支持。必须在元素本身上设置事件处理程序。 (但是,Style类确实支持称为触发器的对象,它可以响应事件或属性更改。触发器在第23章“触发器和行为”中讨论。)
您无法在样式中设置GestureRecognizers属性。这也很有用,但GestureRecognizers不受可绑定属性的支持。
如果可绑定属性是引用类型,并且默认值为null,则可以使用样式将该属性设置为非null对象。但您可能还希望使用将属性设置为null的本地设置覆盖该样式设置。您可以使用{x:Null}标记扩展名在XAML中将属性设置为null。
阅读(2065) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~