3. část: Rozšíření značek XAML
Rozšíření značek XAML představují důležitou funkci XAML, která umožňuje nastavit vlastnosti na objekty nebo hodnoty, na které se odkazuje nepřímo z jiných zdrojů. Rozšíření značek XAML jsou obzvláště důležitá pro sdílení objektů a odkazování na konstanty používané v celé aplikaci, ale v datových vazbách najdou jejich největší nástroj.
Rozšíření značek XAML
Obecně platí, že xaml slouží k nastavení vlastností objektu na explicitní hodnoty, jako je řetězec, číslo, člen výčtu nebo řetězec, který je převeden na hodnotu na pozadí.
Někdy však vlastnosti musí místo toho odkazovat na hodnoty definované někde jinde nebo které mohou vyžadovat malé zpracování kódem za běhu. Pro tyto účely jsou k dispozici rozšíření značek XAML.
Tato rozšíření značek XAML nejsou rozšíření XML. XAML je zcela právní XML. Nazývají se "rozšíření", protože jsou podporovány kódem ve třídách, které implementují IMarkupExtension
. Můžete napsat vlastní rozšíření značek.
V mnoha případech jsou rozšíření značek XAML okamžitě rozpoznatelná v souborech XAML, protože se zobrazují jako nastavení atributů oddělená složenými závorkami: { a }, ale někdy se rozšíření značek zobrazují ve značkách jako konvenční prvky.
Sdílené prostředky
Některé stránky XAML obsahují několik zobrazení s vlastnostmi nastavenými na stejné hodnoty. Například mnoho nastavení vlastnosti pro tyto Button
objekty je stejné:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do that!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do the other thing!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
</StackLayout>
</ContentPage>
Pokud je potřeba některou z těchto vlastností změnit, můžete změnu raději provést jen jednou, a ne třikrát. Pokud by to byl kód, pravděpodobně byste používali konstanty a statické objekty jen pro čtení, které vám pomůžou zachovat takové hodnoty konzistentní a snadno upravit.
Jedním z oblíbených řešení v JAZYCE XAML je uložení takových hodnot nebo objektů ve slovníku prostředků. Třída VisualElement
definuje vlastnost s názvem Resources
typu ResourceDictionary
, což je slovník s klíči typu string
a hodnoty typu object
. Objekty můžete vložit do tohoto slovníku a pak na ně odkazovat z revizí, a to vše v XAML.
Pokud chcete použít slovník prostředků na stránce, zahrňte dvojici značek elementů Resources
vlastností. Nejpohodlnější je umístit je do horní části stránky:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
</ContentPage.Resources>
...
</ContentPage>
Je také nutné explicitně zahrnout ResourceDictionary
značky:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Nyní lze do slovníku prostředků přidat objekty a hodnoty různých typů. Tyto typy musí být okamžité. Nemůžou být například abstraktními třídami. Tyto typy musí mít také veřejný konstruktor bez parametrů. Každá položka vyžaduje klíč slovníku zadaný atributem x:Key
. Příklad:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Tyto dvě položky jsou hodnoty typu LayoutOptions
struktury a každý má jedinečný klíč a jednu nebo dvě sady vlastností. V kódu a kódu je mnohem častější používat statická pole LayoutOptions
, ale zde je vhodnější nastavit vlastnosti.
Teď je potřeba nastavit HorizontalOptions
a VerticalOptions
vlastnosti těchto tlačítek na tyto prostředky a to se provádí s rozšířením StaticResource
značek XAML:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
Rozšíření StaticResource
značek je vždy oddělené složenými závorkami a obsahuje klíč slovníku.
Název StaticResource
jej odlišuje od DynamicResource
, který Xamarin.Forms také podporuje. DynamicResource
je určen pro klíče slovníku přidružené k hodnotám, které se můžou během běhu změnit, zatímco StaticResource
přístup k prvkům ze slovníku jen jednou při vytváření prvků na stránce.
BorderWidth
Pro vlastnost je nutné uložit dvojitou hodnotu ve slovníku. XAML pohodlně definuje značky pro běžné datové typy jako x:Double
a x:Int32
:
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">
3
</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
Nemusíte to dávat na tři řádky. Tato položka slovníku pro tento úhel otočení zabírá pouze jeden řádek:
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">
3
</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
Tyto dva prostředky lze odkazovat stejným způsobem jako na LayoutOptions
hodnoty:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="24" />
Pro prostředky typu Color
můžete použít stejné řetězcové reprezentace, které používáte při přímém přiřazování atributů těchto typů. Převaděče typů jsou vyvolány při vytvoření prostředku. Tady je prostředek typu Color
:
<Color x:Key="textColor">Red</Color>
Programy často nastaví FontSize
vlastnost na člen výčtu NamedSize
, například Large
. Třída FontSizeConverter
pracuje na pozadí a převádí ji na hodnotu závislou na platformě pomocí Device.GetNamedSized
metody. Při definování prostředku velikosti písma ale dává smysl použít číselnou hodnotu, která je zde uvedena x:Double
jako typ:
<x:Double x:Key="fontSize">24</x:Double>
Teď jsou všechny vlastnosti kromě Text
definovaných nastavením prostředků:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
V rámci slovníku prostředků je také možné definovat OnPlatform
různé hodnoty pro platformy. Tady je postup, jak OnPlatform
může být objekt součástí slovníku prostředků pro různé barvy textu:
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>
Všimněte si, že OnPlatform
získá atribut x:Key
, protože se jedná o objekt ve slovníku a x:TypeArguments
atribut, protože se jedná o obecnou třídu. Atributy iOS
a , Android
UWP
jsou převedeny na Color
hodnoty při inicializaci objektu.
Tady je konečný kompletní soubor XAML se třemi tlačítky, která přistupují k šesti sdíleným hodnotám:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">3</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>
<x:Double x:Key="fontSize">24</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do that!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do the other thing!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
</StackLayout>
</ContentPage>
Snímky obrazovky ověřují konzistentní styly a styly závislé na platformě:
Ačkoli je nejběžnější definovat kolekci Resources
v horní části stránky, mějte na paměti, že Resources
vlastnost je definována pomocí VisualElement
a můžete mít Resources
kolekce na jiných prvcích na stránce. Zkuste například přidat jeden do tohoto příkladu StackLayout
:
<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
Zjistíte, že barva textu tlačítek je teď modrá. V podstatě, kdykoli analyzátor XAML narazí na StaticResource
rozšíření značek, vyhledá vizuální strom a použije první ResourceDictionary
, na které narazí obsahující tento klíč.
Jedním z nejběžnějších typů objektů uložených ve slovníkech prostředků je Xamarin.FormsStyle
ten, který definuje kolekci nastavení vlastností. Styly jsou popsány v článku Styly.
Vývojáři, kteří s JAZYKem XAML noví, se někdy diví, jestli můžou vložit vizuální prvek, jako Label
je nebo Button
do ResourceDictionary
. I když je to jistě možné, nedává moc smysl. Účelem je ResourceDictionary
sdílet objekty. Prvek vizuálu nelze sdílet. Stejná instance se nemůže na jedné stránce objevit dvakrát.
Rozšíření x:Static Markup
Navzdory podobnostem jejich jmen x:Static
a StaticResource
jsou velmi odlišné. StaticResource
vrátí objekt ze slovníku prostředků, zatímco x:Static
přistupuje k jedné z následujících možností:
- veřejné statické pole
- veřejná statická vlastnost
- pole veřejné konstanty
- člen výčtu.
Rozšíření StaticResource
značek je podporováno implementacemi XAML, které definují slovník prostředků, zatímco x:Static
je vnitřní součástí XAML, jak se předpona x
odhalí.
Tady je několik příkladů, které ukazují, jak x:Static
explicitně odkazovat na statická pole a členy výčtu:
<Label Text="Hello, XAML!"
VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Color.Aqua}" />
Zatím to není moc působivé. x:Static
Rozšíření značek ale může také odkazovat na statická pole nebo vlastnosti z vlastního kódu. Tady je AppConstants
například třída, která obsahuje některá statická pole, která můžete chtít použít na více stránkách v celé aplikaci:
using System;
using Xamarin.Forms;
namespace XamlSamples
{
static class AppConstants
{
public static readonly Thickness PagePadding;
public static readonly Font TitleFont;
public static readonly Color BackgroundColor = Color.Aqua;
public static readonly Color ForegroundColor = Color.Brown;
static AppConstants()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
PagePadding = new Thickness(5, 20, 5, 0);
TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
break;
case Device.Android:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
break;
case Device.UWP:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
break;
}
}
}
}
Pokud chcete odkazovat na statická pole této třídy v souboru XAML, budete potřebovat nějaký způsob, jak označit v souboru XAML, kde se tento soubor nachází. Provedete to s deklarací oboru názvů XML.
Vzpomeňte si, že soubory XAML vytvořené jako součást standardní Xamarin.Forms šablony XAML obsahují dvě deklarace oboru názvů XML: jednu pro přístup ke Xamarin.Forms třídám a druhou pro odkazování na značky a atributy vnitřní do XAML:
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Pro přístup k jiným třídám budete potřebovat další deklarace oboru názvů XML. Každá další deklarace oboru názvů XML definuje novou předponu. Pro přístup ke třídám místnímu ke sdílené knihovně .NET Standard aplikace, jako AppConstants
je například , programátoři XAML často používají předponu local
. Deklarace oboru názvů musí obsahovat název oboru názvů CLR (Common Language Runtime), označovaný také jako název oboru názvů .NET, což je název, který se zobrazuje v definici jazyka C# namespace
nebo v direktivě using
:
xmlns:local="clr-namespace:XamlSamples"
Deklarace oboru názvů XML můžete také definovat pro obory názvů .NET v libovolném sestavení, na které odkazuje knihovna .NET Standard. Tady je sys
například předpona standardního oboru názvů .NET System
, který je ve standardním sestavení netstandard . Vzhledem k tomu, že se jedná o jiné sestavení, musíte také zadat název sestavení, v tomto případě netstandard:
xmlns:sys="clr-namespace:System;assembly=netstandard"
Všimněte si, že za tímto klíčovým slovem clr-namespace
následuje dvojtečka a název oboru názvů .NET, za kterým následuje středník, klíčové slovo assembly
, znaménko rovná se a název sestavení.
Ano, dvojtečka následuje clr-namespace
, ale rovnítko následuje assembly
. Syntaxe byla definována tímto způsobem záměrně: Většina deklarací oboru názvů XML odkazuje na identifikátor URI, který začíná název schématu identifikátoru URI, například http
, který je vždy následovaný dvojtečka. Součástí clr-namespace
tohoto řetězce je napodobování této konvence.
Obě tyto deklarace oboru názvů jsou součástí ukázky StaticConstantsPage . Všimněte si, že BoxView
dimenze jsou nastaveny na Math.PI
a Math.E
, ale škálovány faktorem 100:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="XamlSamples.StaticConstantsPage"
Title="Static Constants Page"
Padding="{x:Static local:AppConstants.PagePadding}">
<StackLayout>
<Label Text="Hello, XAML!"
TextColor="{x:Static local:AppConstants.BackgroundColor}"
BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
Font="{x:Static local:AppConstants.TitleFont}"
HorizontalOptions="Center" />
<BoxView WidthRequest="{x:Static sys:Math.PI}"
HeightRequest="{x:Static sys:Math.E}"
Color="{x:Static local:AppConstants.ForegroundColor}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="100" />
</StackLayout>
</ContentPage>
Velikost výsledného BoxView
výsledku vzhledem k obrazovce je závislá na platformě:
Další standardní rozšíření značek
V souborech XAML je vnitřních několik rozšíření značek a podporuje se v Xamarin.Forms souborech XAML. Některé z nich se velmi často nepoužívají, ale jsou nezbytné, pokud je potřebujete:
- Pokud vlastnost má ve výchozím nastavení jinou hodnotu
null
, ale chcete ji nastavit nanull
, nastavte ji na{x:Null}
rozšíření značek. - Pokud je vlastnost typu
Type
, můžete ji přiřadit k objektuType
pomocí rozšíření{x:Type someClass}
značek . - Pole v XAML můžete definovat pomocí
x:Array
rozšíření značek. Toto rozšíření značek má požadovaný atribut,Type
který označuje typ prvků v poli. - Rozšíření
Binding
značek je popsáno v části 4. Základy datových vazeb - Rozšíření
RelativeSource
značek je popsáno v relativních vazbách.
Rozšíření značek ConstraintExpression
Rozšíření značek můžou mít vlastnosti, ale nejsou nastavené jako atributy XML. V rozšíření značek jsou nastavení vlastností oddělená čárkami a ve složených závorkách se nezobrazují žádné uvozovky.
To lze ilustrovat s příponou Xamarin.Forms značek s názvem ConstraintExpression
, který se používá s RelativeLayout
třídou. Umístění nebo velikost podřízeného zobrazení můžete zadat jako konstantu nebo relativní k nadřazené nebo jiné pojmenované zobrazení. Syntaxe ConstraintExpression
umožňuje nastavit pozici nebo velikost zobrazení pomocí Factor
časů vlastnosti jiného zobrazení a navíc Constant
. Cokoli složitějšího, než vyžaduje kód.
Tady je příklad:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.RelativeLayoutPage"
Title="RelativeLayout Page">
<RelativeLayout>
<!-- Upper left -->
<BoxView Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Upper right -->
<BoxView Color="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Lower left -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Lower right -->
<BoxView Color="Yellow"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Centered and 1/3 width and height of parent -->
<BoxView x:Name="oneThird"
Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}" />
<!-- 1/3 width and height of previous -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=X}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Y}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Height,
Factor=0.33}" />
</RelativeLayout>
</ContentPage>
Možná nejdůležitější lekcí, kterou byste měli vzít z této ukázky, je syntaxe rozšíření značek: V závorkách s příponou značek se nesmí objevit žádné uvozovky. Při zadávání přípony značek do souboru XAML je přirozené, že chcete uzavřít hodnoty vlastností do uvozovek. Odporujte pokušení!
Tady je spuštěný program:
Shrnutí
Zde uvedené rozšíření značek XAML poskytují důležitou podporu pro soubory XAML. Ale možná nejužitečnější rozšíření kódu XAML je Binding
, které je popsáno v další části této série, část 4. Základy datových vazeb