第 3 部 XAML マークアップ拡張
XAML マークアップ拡張機能は、他のソースから間接的に参照されるオブジェクトまたは値にプロパティを設定できるようにする XAML の重要な機能です。 XAML マークアップ拡張機能は、オブジェクトを共有したり、アプリケーション全体で使用される定数を参照したりするために特に重要ですが、データ バインディングで最も優れたユーティリティが見つかります。
XAML マークアップ拡張
一般に、XAML を使用して、オブジェクトのプロパティを明示的な値 (文字列、数値、列挙メンバー、またはバックグラウンドの値に変換される文字列など) に設定します。
ただし、プロパティが他の場所で定義されている値を参照する必要がある場合や、実行時にコードによる処理が少し必要になる場合があります。 このような目的で、XAML マークアップ拡張機能 を使用できます。
これらの XAML マークアップ拡張機能は XML の拡張機能ではありません。 XAML は完全に有効な XML です。 これらは、 を実装 IMarkupExtension
するクラスのコードによってサポートされるため、"拡張機能" と呼ばれます。 独自のカスタム マークアップ拡張機能を記述できます。
多くの場合、XAML マークアップ拡張機能は、中かっこ { と }で区切られた属性設定として表示されますが、マークアップ拡張機能がマークアップで従来の要素として表示される場合があるため、XAML ファイルですぐに認識できます。
共有リソース
一部の XAML ページには、プロパティが同じ値に設定された複数のビューが含まれています。 たとえば、これらの Button
オブジェクトのプロパティ設定の多くは同じです。
<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>
これらのプロパティのいずれかを変更する必要がある場合は、変更を 3 回ではなく 1 回だけ行う必要があります。 これがコードの場合は、定数と静的な読み取り専用オブジェクトを使用して、このような値の一貫性と変更を容易に保つことができます。
XAML では、一般的な解決策の 1 つは、このような値またはオブジェクトを リソース ディクショナリに格納することです。 クラスは VisualElement
、 型 という名前 Resources
のプロパティを定義します。これは、 型 ResourceDictionary
のキーと 型 string
の object
値を持つディクショナリです。 このディクショナリにオブジェクトを配置し、XAML でマークアップから参照できます。
ページでリソース ディクショナリを使用するには、プロパティ要素タグの Resources
ペアを含めます。 これらはページの上部に配置するのが最も便利です。
<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>
タグを明示的に含める ResourceDictionary
必要もあります。
<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>
さまざまな型のオブジェクトと値をリソース ディクショナリに追加できるようになりました。 これらの型は即時可能である必要があります。 たとえば、抽象クラスにすることはできません。 これらの型には、パラメーターなしのパブリック コンストラクターも必要です。 各項目には、 属性で指定されたディクショナリ キーが x:Key
必要です。 次に例を示します。
<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>
これら 2 つの項目は構造体型 LayoutOptions
の値であり、それぞれに一意のキーと 1 つまたは 2 つのプロパティが設定されています。 コードとマークアップでは、 の静的フィールド LayoutOptions
を使用する方がはるかに一般的ですが、ここではプロパティを設定する方が便利です。
次に、これらのボタンの プロパティと VerticalOptions
プロパティをこれらのリソースに設定HorizontalOptions
する必要があります。これは XAML マークアップ拡張機能を使用してStaticResource
行われます。
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
StaticResource
マークアップ拡張機能は常に中かっこで区切られ、ディクショナリ キーが含まれます。
この名前 StaticResource
は、 と区別 DynamicResource
されます。これも Xamarin.Forms サポートしています。 DynamicResource
は、実行時に変更される可能性がある値に関連付けられているディクショナリ キーを対象とします。一方 StaticResource
、ページ上の要素が構築されると、ディクショナリから 1 回だけ要素にアクセスします。
プロパティの BorderWidth
場合は、ディクショナリに double を格納する必要があります。 XAML は、 や x:Int32
のようなx:Double
一般的なデータ型のタグを簡単に定義します。
<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>
3 行に配置する必要はありません。 この回転角度のこの辞書エントリは、1 行のみを占めます。
<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>
これらの 2 つのリソースは、値と同じ方法 LayoutOptions
で参照できます。
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="24" />
型のリソースでは、これらの型 Color
の属性を直接割り当てるときに使用するのと同じ文字列表現を使用できます。 型コンバーターは、リソースの作成時に呼び出されます。 型のリソースを次に示します Color
。
<Color x:Key="textColor">Red</Color>
多くの場合、プログラムはFontSize
、 などのLarge
列挙体のメンバーにプロパティをNamedSize
設定します。 クラスは FontSizeConverter
バックグラウンドで動作し、 メソッドを使用して Device.GetNamedSized
プラットフォームに依存する値に変換します。 ただし、フォント サイズ リソースを定義する場合は、次のように型として示す数値を使用する方が理に x:Double
かなっています。
<x:Double x:Key="fontSize">24</x:Double>
を除く Text
すべてのプロパティは、リソース設定によって定義されます。
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
また、リソース ディクショナリ内で を使用 OnPlatform
して、プラットフォームのさまざまな値を定義することもできます。 オブジェクトを OnPlatform
さまざまなテキストの色のリソース ディクショナリに含める方法を次に示します。
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>
OnPlatform
ディクショナリ内のオブジェクトであるため属性とx:Key
、ジェネリック クラスであるため属性の両方をx:TypeArguments
取得していることに注意してください。 、Android
、および UWP
属性はiOS
、オブジェクトの初期化時にColor
値に変換されます。
6 つの共有値にアクセスする 3 つのボタンを含む最終的な完全な XAML ファイルを次に示します。
<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>
スクリーンショットでは、一貫性のあるスタイル設定と、プラットフォームに依存するスタイルを確認します。
ページの上部にコレクションをResources
定義するのが最も一般的ですが、 プロパティは によってVisualElement
定義され、ページ上の他の要素にコレクションを含Resources
めることができることにResources
注意してください。 たとえば、次の例の に 1 つを StackLayout
追加してみてください。
<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
ボタンのテキストの色が青になっていることがわかります。 基本的には、XAML パーサーがマークアップ拡張機能を StaticResource
検出するたびに、ビジュアル ツリーを検索し、そのキーを含む最初 ResourceDictionary
に検出された を使用します。
リソース ディクショナリ Xamarin.FormsStyle
に格納されているオブジェクトの最も一般的な種類の 1 つは、 で、プロパティ設定のコレクションを定義します。 スタイルについては、「スタイル」を参照 してください。
XAML を初めて使用する開発者は、 や などのLabel
Button
ビジュアル要素を に配置できるかどうかを疑問にResourceDictionary
思うことがあります。 確かに可能ですが、あまり意味がありません。 の ResourceDictionary
目的は、オブジェクトを共有することです。 ビジュアル要素は共有できません。 同じインスタンスを 1 つのページに 2 回表示することはできません。
x:Static マークアップ拡張機能
彼らの名前の類似点にもかかわらず、 x:Static
と StaticResource
は非常に異なります。 StaticResource
はリソース ディクショナリから オブジェクトを返しますが、 x:Static
次のいずれかにアクセスします。
- パブリック静的フィールド
- パブリック静的プロパティ
- パブリック定数フィールド
- 列挙メンバー。
StaticResource
マークアップ拡張機能は、リソース ディクショナリを定義する XAML 実装でサポートされていますが、x:Static
プレフィックスが明らかにするように x
XAML の組み込み部分です。
静的フィールドと列挙メンバーを明示的に参照する方法 x:Static
を示す例をいくつか次に示します。
<Label Text="Hello, XAML!"
VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Color.Aqua}" />
今のところ、これはあまり印象的ではありません。 ただし、マークアップ拡張機能は、独自の x:Static
コードから静的フィールドまたはプロパティを参照することもできます。 たとえば、アプリケーション全体で複数の AppConstants
ページで使用する静的フィールドを含むクラスを次に示します。
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;
}
}
}
}
XAML ファイルでこのクラスの静的フィールドを参照するには、このファイルが配置されている XAML ファイル内でを示す何らかの方法が必要です。 これを行うには、XML 名前空間宣言を使用します。
標準 Xamarin.Forms XAML テンプレートの一部として作成された XAML ファイルには、クラスへのアクセス用と XAML に組み込まれているタグと属性の Xamarin.Forms 参照用の 2 つの XML 名前空間宣言が含まれていることを思い出してください。
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
他のクラスにアクセスするには、追加の XML 名前空間宣言が必要です。 追加の XML 名前空間宣言ごとに、新しいプレフィックスが定義されます。 などの AppConstants
共有アプリケーション .NET Standard ライブラリのローカルクラスにアクセスするには、XAML プログラマは多くの場合、プレフィックス local
を使用します。 名前空間宣言は、CLR (共通言語ランタイム) 名前空間名 (.NET 名前空間名とも呼ばれます) を示す必要があります。これは、C# namespace
定義またはディレクティブに using
表示される名前です。
xmlns:local="clr-namespace:XamlSamples"
.NET Standard ライブラリが参照する任意のアセンブリで、.NET 名前空間の XML 名前空間宣言を定義することもできます。 たとえば、netstandard アセンブリにある標準の .NET System
名前空間のプレフィックスを次sys
に示します。 これは別のアセンブリであるため、アセンブリ名 (この場合は netstandard) も指定する必要があります。
xmlns:sys="clr-namespace:System;assembly=netstandard"
キーワード (keyword)clr-namespace
の後にコロン、.NET 名前空間名、セミコロン、キーワード (keyword)assembly
、等号、アセンブリ名が続きます。
はい。コロンは の後に続きます clr-namespace
が、等号は の後に続きます assembly
。 構文は意図的に定義されました。ほとんどの XML 名前空間宣言は、 などの http
URI スキーム名を開始する URI を参照します。これは常にコロンが続きます。 この文字列の部分は clr-namespace
、その規則を模倣することを目的としています。
これらの名前空間宣言はどちらも StaticConstantsPage サンプルに含まれています。 ディメンションは BoxView
と Math.E
にMath.PI
設定されていますが、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>
画面に対する相対的な BoxView
結果のサイズは、プラットフォームに依存します。
その他の標準マークアップ拡張機能
いくつかのマークアップ拡張機能は XAML に組み込まれており、XAML ファイルで Xamarin.Forms サポートされています。 これらの一部は頻繁に使用されませんが、必要な場合は不可欠です。
- プロパティに既定では値
null
以外の値があるが、 にnull
設定する場合は、マークアップ拡張機能に{x:Null}
設定します。 - プロパティが 型
Type
の場合は、マークアップ拡張{x:Type someClass}
をType
使用してオブジェクトに割り当てることができます。 - XAML では、マークアップ拡張機能を使用して配列を
x:Array
定義できます。 このマークアップ拡張には、配列内の要素の型を示す という名前Type
の必須属性があります。 - マークアップ拡張機能については
Binding
、 パート 4 で説明します。データ バインディングの基本。 - マークアップ拡張機能については
RelativeSource
、「 相対バインディング」を参照してください。
ConstraintExpression マークアップ拡張機能
マークアップ拡張機能はプロパティを持つことができますが、XML 属性のように設定されません。 マークアップ拡張機能では、プロパティ設定はコンマで区切られ、中かっこ内に引用符は表示されません。
これは、 クラスで使用される という名前ConstraintExpression
のXamarin.Formsマークアップ拡張機能でRelativeLayout
示すことができます。 子ビューの場所またはサイズを定数として指定することも、親ビューやその他の名前付きビューを基準にして指定することもできます。 のConstraintExpression
構文を使用すると、ビューの位置またはサイズを、別のビューのプロパティに 加えて Constant
を使用してFactor
設定できます。 コードを必要とするよりも複雑なもの。
次に例を示します。
<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>
おそらく、このサンプルから取るべき最も重要なレッスンは、マークアップ拡張機能の構文です。マークアップ拡張機能の中かっこ内に引用符を含める必要はありません。 XAML ファイルにマークアップ拡張機能を入力するときは、プロパティの値を引用符で囲むのが自然です。 誘惑に抵抗!
実行されているプログラムを次に示します。
まとめ
ここに示す XAML マークアップ拡張機能は、XAML ファイルの重要なサポートを提供します。 しかし、おそらく最も重要な XAML マークアップ拡張機能は Binding
です。これは、このシリーズの次のパートである パート 4 で説明します。データ バインディングの基本。