天天看點

第十章: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事件,并且通常按鈕文本不是拉丁文。 但這是他們的樣子:

第十章:XAML标記擴充(三)資源詞典

除文本外,所有三個按鈕都具有相同的屬性設定為相同的值。 像這樣的重複标記往往會錯誤地影響程式員。 這是對眼睛的冒犯,難以維持和改變。

最終你會看到如何使用樣式來真正減少重複标記。 現在,怎麼樣?目标不是縮短标記,而是将值合并到一個地方,這樣如果你想将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章中探讨。

繼續閱讀