天天看點

第十章:XAML标記擴充(二)通路靜态成員

通路靜态成員

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繼承與字型相關的設定。

這是:

第十章:XAML标記擴充(二)通路靜态成員

此技術允許您在多個頁面上使用這些公共屬性設定,如果您需要更改值,則隻需更改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機關寬,但斷線肯定有效:

第十章:XAML标記擴充(二)通路靜态成員

使用花括号進行标記擴充意味着您無法顯示由花括号括起來的文本。 本文中的花括号将被誤認為是标記擴充名:

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

那不行。 您可以在文本字元串中的其他位置使用花括号,但不能以左大括号開頭。

但是,如果确實需要,可以通過使用由左右一對花括号組成的轉義序列開始文本,確定文本不會被誤認為是XAML标記擴充:

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

這将顯示您想要的文本。

繼續閱讀