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

简介: 访问静态成员 IMarkupExtension最简单和最有用的实现之一封装在StaticExtension类中。 这是原始XAML规范的一部分,因此它通常出现在带有x前缀的XAML中。 StaticExtension定义了一个名为Member of string的属性,您可以将其设置为公共常量,静态属性,静态字段或枚举成员的类和成员名称。

访问静态成员

IMarkupExtension最简单和最有用的实现之一封装在StaticExtension类中。 这是原始XAML规范的一部分,因此它通常出现在带有x前缀的XAML中。 StaticExtension定义了一个名为Member of string的属性,您可以将其设置为公共常量,静态属性,静态字段或枚举成员的类和成员名称。
让我们看看它是如何工作的。 这是一个标签,其中六个属性设置为通常在XAML中显示的属性:

<Label Text="Just some text"
       BackgroundColor="Accent"
       TextColor="Black"
       FontAttributes="Italic"
       VerticalOptions="Center"
       HorizontalTextAlignment="Center" />

其中五个属性设置为最终引用各种静态属性,字段和枚举成员的文本字符串,但这些文本字符串的转换通过类型转换器和枚举类型的标准XAML解析进行。
如果您希望更明确地将这些属性设置为各种静态属性,字段和枚举成员,则可以在属性元素标记中使用x:StaticExtension:

<Label Text="Just some text">
    <Label.BackgroundColor>
        <x:StaticExtension Member="Color.Accent" />
    </Label.BackgroundColor>
    <Label.TextColor>
        <x:StaticExtension Member="Color.Black" />
    </Label.TextColor>
    <Label.FontAttributes>
        <x:StaticExtension Member="FontAttributes.Italic" />
    </Label.FontAttributes>
    <Label.VerticalOptions>
        <x:StaticExtension Member="LayoutOptions.Center" />
    </Label.VerticalOptions>
    <Label.HorizontalTextAlignment>
        <x:StaticExtension Member="TextAlignment.Center" />
    </Label.HorizontalTextAlignment>
</Label>

Color.Accent是一个静态属性。 Color.Black和LayoutOptions.Center是静态字段。 FontAttributes.Italic和TextAlignment.Center是枚举成员。
考虑到使用文本字符串设置这些属性的难易程度,使用Stat?icExtension的方法最初看起来很荒谬,但请注意它是一种通用机制。 如果StaticExtension标记的类型与target属性的类型匹配,则可以使用StaticExtension标记中的任何静态属性,字段或枚举成员。
按照惯例,实现IMarkupExtension的类在其名称中包含单词Extension,但您可以将其保留在XAML中,这就是为什么此标记扩展通常称为x:Static而不是x:StaticExtension。 以下标记略微短于前一个块:

<Label Text="Just some text">
    <Label.BackgroundColor>
        <x:Static Member="Color.Accent" />
    </Label.BackgroundColor>
    <Label.TextColor>
        <x:Static Member="Color.Black" />
    </Label.TextColor>
    <Label.FontAttributes>
        <x:Static Member="FontAttributes.Italic" />
    </Label.FontAttributes>
    <Label.VerticalOptions>
        <x:Static Member="LayoutOptions.Center" />
    </Label.VerticalOptions>
    <Label.HorizontalTextAlignment>
        <x:Static Member="TextAlignment.Center" />
    </Label.HorizontalTextAlignment>
</Label>

现在,对于真正重大的主要 - 语法的改变导致属性元素标签消失,占用空间大大缩小。 XAML标记扩展几乎与标记扩展名和一对花括号中的参数一起出现:

<Label Text="Just some text"
       BackgroundColor="{x:Static Member=Color.Accent}"
       TextColor="{x:Static Member=Color.Black}"
       FontAttributes="{x:Static Member=FontAttributes.Italic}"
       VerticalOptions="{x:Static Member=LayoutOptions.Center}"
       HorizontalTextAlignment="{x:Static Member=TextAlignment.Center}" />

这种带有花括号的语法无处不在地与XAML标记扩展一起使用,许多开发人员认为标记扩展与大括号语法同义。 这几乎是正确的:虽然花括号总是表示存在XAML标记扩展,但在许多情况下,标记扩展可以在没有花括号的XAML中出现(如前所示),并且有时可以方便地使用它们。
staticExtension类的operty不再是XML属性。 就XML而言,由花括号分隔的整个表达式是属性的值,并且花括号内的参数不带引号。
就像元素一样,标记扩展可以具有ContentProperty属性。 仅具有一个属性的标记扩展(例如具有单个成员属性的StaticExtension类)始终将该唯一属性标记为内容属性。 对于使用卷括号语法的标记扩展,这意味着可以删除成员属性名称和等号:

<Label Text="Just some text"
       BackgroundColor="{x:Static Color.Accent}"
       TextColor="{x:Static Color.Black}"
       FontAttributes="{x:Static FontAttributes.Italic}"
       VerticalOptions="{x:Static LayoutOptions.Center}"
       HorizontalTextAlignment="{x:Static TextAlignment.Center}" />

这是x:Static标记扩展的常见形式。
显然,不需要对这些特定属性使用x:Static,但是您可以定义自己的静态成员来实现应用程序范围的常量,并且可以在XAML文件中引用它们。 这在SharedStatics项目中得到了证明。
SharedStatics项目包含一个名为AppConstants的类,它定义了一些可能用于格式化文本的常量和静态字段:

namespace SharedStatics
{
    static class AppConstants
    {
        public static Color LightBackground = Color.Yellow; 
        public static Color DarkForeground = Color.Blue;
        public static double NormalFontSize = 18;
        public static double TitleFontSize = 1.4 * NormalFontSize;
        public static double ParagraphSpacing = 10;
        public const FontAttributes Emphasis = FontAttributes.Italic;
        public const FontAttributes TitleAttribute = FontAttributes.Bold;
        public const TextAlignment TitleAlignment = TextAlignment.Center;
    }
}

如果每个平台需要不同的东西,可以在这些定义中使用Device.OnPlatform。
然后,XAML文件使用18 x:静态标记扩展来引用这些项。 请注意将本地前缀与项目命名空间相关联的XML名称空间声明:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SharedStatics"
             x:Class="SharedStatics.SharedStaticsPage"
             BackgroundColor="{x:Static local:AppConstants.LightBackground}">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
    <StackLayout Padding="10, 0"
                 Spacing="{x:Static local:AppConstants.ParagraphSpacing}">
 
        <Label Text="The SharedStatics Program" 
               TextColor="{x:Static local:AppConstants.DarkForeground}"
               FontSize="{x:Static local:AppConstants.TitleFontSize}"
               FontAttributes="{x:Static local:AppConstants.TitleAttribute}"
               HorizontalTextAlignment="{x:Static local:AppConstants.TitleAlignment}" />
        <Label TextColor="{x:Static local:AppConstants.DarkForeground}"
               FontSize="{x:Static local:AppConstants.NormalFontSize}">
            <Label.FormattedText>
                <FormattedString>
                    <Span Text="Through use of the " />
                    <Span Text="x:Static"
                          FontSize="{x:Static local:AppConstants.NormalFontSize}"
                          FontAttributes="{x:Static local:AppConstants.Emphasis}" />
                    <Span Text=
" XAML markup extension, an application can maintain a collection of 
common property settings defined as constants, static properties or fields, 
or enumeration members in a separate code file. These can then be
referenced within the XAML file." />
                </FormattedString>
            </Label.FormattedText>
        </Label>
        <Label TextColor="{x:Static local:AppConstants.DarkForeground}"
               FontSize="{x:Static local:AppConstants.NormalFontSize}">
            <Label.FormattedText>
                <FormattedString>
                    <Span Text=
"However, this is not the only technique to share property settings.
You'll soon discover that you can store objects in a " />
                        <Span Text="ResourceDictionary"
                          FontSize="{x:Static local:AppConstants.NormalFontSize}"
                          FontAttributes="{x:Static local:AppConstants.Emphasis}" />
                    <Span Text=" and access them through the " />
                    <Span Text="StaticResource"
                          FontSize="{x:Static local:AppConstants.NormalFontSize}"
                          FontAttributes="{x:Static local:AppConstants.Emphasis}" />
                    <Span Text=
" markup extension, and even encapsultate multiple property settings in a " />
                    <Span Text="Style"
                          FontSize="{x:Static local:AppConstants.NormalFontSize}"
                          FontAttributes="{x:Static local:AppConstants.Emphasis}" />
                    <Span Text=" object." />
                </FormattedString>
            </Label.FormattedText>
        </Label> 
    </StackLayout>
</ContentPage>

具有FontAttributes设置的每个Span对象都会重复在Label本身上设置的FontSize设置,因为当应用其他与字体相关的设置时,Span对象不会从Label继承与字体相关的设置。
这是:
201807242140090352
此技术允许您在多个页面上使用这些公共属性设置,如果您需要更改值,则只需更改AppSettings文件。
也可以使用x:Static和静态属性以及在外部li?braries中的类中定义的字段。 下面的示例名为SystemStatics,它设计得非常合适 - 它将Button的BorderWidth设置为等于Math类中定义的PI静态字段,并使用静态Environment.New?Line属性来处理文本中的换行符。 但它证明了这项技术。
Math和Environment类都在.NET System命名空间中定义,因此需要新的XML命名空间声明来定义名为(例如)sys for System的前缀。 请注意,此命名空间声明将CLR命名空间指定为System,但将程序集指定为mscorlib,它最初代表Microsoft公共对象运行时库,但现在代表多语言标准公共对象运行时库:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             x:Class="SystemStatics.SystemStaticsPage">
    <StackLayout>
        <Button Text=" Button with &#x03C0; border width "
                BorderWidth="{x:Static sys:Math.PI}"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand">
            <Button.BackgroundColor>
                <OnPlatform x:TypeArguments="Color"
                            Android="#404040" />
            </Button.BackgroundColor> 
            <Button.BorderColor>
                <OnPlatform x:TypeArguments="Color"
                            Android="White"
                            WinPhone="Black" />
            </Button.BorderColor>
        </Button>
        <Label VerticalOptions="CenterAndExpand"
               HorizontalTextAlignment="Center"
               FontSize="Medium">
            <Label.FormattedText>
                <FormattedString>
                    <Span Text="Three lines of text" />
                    <Span Text="{x:Static sys:Environment.NewLine}" />
                    <Span Text="separated by" />
                    <Span Text="{x:Static sys:Environment.NewLine}" />
                    <Span Text="Environment.NewLine"
                          FontSize="Medium"
                          FontAttributes="Italic" />
                    <Span Text=" strings" />
                </FormattedString>
            </Label.FormattedText>
        </Label>
    </StackLayout>
</ContentPage>

除非设置了背景颜色,否则按钮边框不会显示在Android中,并且在An?droid和Windows Phone上边框都需要非默认颜色,因此一些额外的标记可以解决这些问题。 在iOS平台上,按钮边框往往会挤压按钮文本,因此文本在开头和结尾都定义了空格。
仅从视觉效果来判断,我们必须相信按钮边框宽度约为3.14单位宽,但断线肯定有效:
201807242142260353
使用花括号进行标记扩展意味着您无法显示由花括号括起来的文本。 本文中的花括号将被误认为是标记扩展名:

<Label Text="{Text in curly braces}" />

那不行。 您可以在文本字符串中的其他位置使用花括号,但不能以左大括号开头。
但是,如果确实需要,可以通过使用由左右一对花括号组成的转义序列开始文本,确保文本不会被误认为是XAML标记扩展:

<Label Text="{}{Text in curly braces}" />

这将显示您想要的文本。

目录
相关文章
|
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开发
|
存储 JavaScript Android开发
第十章:XAML标记扩展(三)
资源词典 Xamarin.Forms还支持第二种共享对象和值的方法,虽然这种方法比x:静态标记扩展稍微有点开销,但它更通用 - 因为所有东西 - 共享对象和使用的可视元素 它们 - 可以用XAML表示。
1194 0
|
JavaScript Android开发 Windows