第十章:XAML标记扩展(三)

简介: 资源词典 Xamarin.Forms还支持第二种共享对象和值的方法,虽然这种方法比x:静态标记扩展稍微有点开销,但它更通用 - 因为所有东西 - 共享对象和使用的可视元素 它们 - 可以用XAML表示。

资源词典

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事件,并且通常按钮文本不是拉丁文。 但这是他们的样子:
201807252129360354
除文本外,所有三个按钮都具有相同的属性设置为相同的值。 像这样的重复标记往往会错误地影响程序员。 这是对眼睛的冒犯,难以维持和改变。
最终你会看到如何使用样式来真正减少重复标记。 现在,怎么样?目标不是缩短标记,而是将值合并到一个地方,这样如果你想将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章中探讨。

目录
相关文章
|
C#
避免让WPF资源字典变得杂乱臃肿
原文:避免让WPF资源字典变得杂乱臃肿                   避免让WPF资源字典变得杂乱臃肿                           周银辉 今天看到项目种的一个XXXResource.xaml文件代码有二千多行,这引发了我一些思考:如何组织我们的WPF资源。
1132 0
|
4月前
|
容器 C# 开发者
XAML语言大揭秘:WPF标记的魅力所在,让你轻松实现界面与逻辑分离,告别复杂代码!
【8月更文挑战第31天】XAML提供了一种直观且易于维护的界面设计方式,使得开发者可以专注于逻辑和业务代码的编写,而无需关心界面细节。通过数据绑定、布局管理和动画效果等特性,XAML可以实现丰富的界面交互和视觉效果。在实际开发过程中,开发者应根据具体需求选择合适的技术方案,以确保应用程序能够满足用户的需求。希望本文的内容能够帮助您在WPF应用程序开发中更好地利用XAML语言。
48 0
|
C#
艾伟:Silverlight 里如何实现隐式样式,ImplicitStyleManager 的实现思想
在 WPF 中,我们可以方便的在全局范围定义一个样式,就可以应用到所有这种类型的对象,这就是所谓的隐式样式(implicit Style),比如: WPF中定义样式 Button aButton b 这样之后,两个按钮就都变成了浅蓝色的背景。
963 0
|
C#
艾伟_转载:WPF/Silverlight陷阱:XAML自定义控件的嵌套内容无法通过名称访问
为了说明这个问题,假定我们需要实现一个具有特殊功能的按钮控件。编写Xaml文件如下: Button> 对 Code Behind类,唯一的改动是把向导生成的基类从UserControl改成Button: public partial class XamlButton : Button{    ...
1083 0
|
C# Windows
WPF中如何选择合适的元数据标记?(英文)
原文:WPF中如何选择合适的元数据标记?(英文) FrameworkPropertyMetadataOptions Enumeration:Specifies the types of framework-level p...
964 0
|
JavaScript Android开发
|
JavaScript 数据可视化 Android开发
|
XML JavaScript Android开发
第十章:XAML标记扩展(二)
访问静态成员 IMarkupExtension最简单和最有用的实现之一封装在StaticExtension类中。 这是原始XAML规范的一部分,因此它通常出现在带有x前缀的XAML中。 StaticExtension定义了一个名为Member of string的属性,您可以将其设置为公共常量,静态属性,静态字段或枚举成员的类和成员名称。
1061 0
|
JavaScript Android开发 Windows