XAML マークアップ拡張の作成
プログラムのレベルでは、XAML マークアップ拡張は、IMarkupExtension
または IMarkupExtension<T>
インターフェイスを実装するクラスです。 Xamarin.Forms GitHub リポジトリの MarkupExtensions ディレクトリで、以下で説明する標準マークアップ拡張のソース コードを確認できます。
IMarkupExtension
または IMarkupExtension<T>
から独自のカスタム XAML マークアップ拡張を定義することもできます。 マークアップ拡張機能が特定の型の値を取得する場合は、ジェネリック フォームを使用します。 これは、次のようないくつかの Xamarin.Forms マークアップ拡張に当てはまります。
TypeExtension
は、IMarkupExtension<Type>
から派生しますArrayExtension
は、IMarkupExtension<Array>
から派生しますDynamicResourceExtension
は、IMarkupExtension<DynamicResource>
から派生しますBindingExtension
は、IMarkupExtension<BindingBase>
から派生しますConstraintExpression
は、IMarkupExtension<Constraint>
から派生します
2 つの IMarkupExtension
インターフェイスは、ProvideValue
という名前のそれぞれ 1 つのメソッドのみを定義します。
public interface IMarkupExtension
{
object ProvideValue(IServiceProvider serviceProvider);
}
public interface IMarkupExtension<out T> : IMarkupExtension
{
new T ProvideValue(IServiceProvider serviceProvider);
}
IMarkupExtension<T>
は IMarkupExtension
から派生し、ProvideValue
の new
キーワードが含まれているので、両方の ProvideValue
メソッドが含まれます。
多くの場合、XAML マークアップ拡張は、戻り値に寄与するプロパティを定義します。 (明らかな例外は NullExtension
です。この場合、ProvideValue
によって単に null
が返されます。)ProvideValue
メソッドには、この記事の後半で説明する IServiceProvider
型の 1 つの引数があります。
色を指定するためのマークアップ拡張
次の XAML マークアップ拡張を使用すると、色相、彩度、および明度の各コンポーネントを使用して Color
値を構築できます。 これは、色の 4 つのコンポーネントの 4 つのプロパティを定義します。1 に初期化されるアルファ コンポーネントも含まれます。 このクラスは、IMarkupExtension<Color>
から派生し、Color
戻り値を示します。
public class HslColorExtension : IMarkupExtension<Color>
{
public double H { set; get; }
public double S { set; get; }
public double L { set; get; }
public double A { set; get; } = 1.0;
public Color ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromHsla(H, S, L, A);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}
IMarkupExtension<T>
は IMarkupExtension
から派生しているため、クラスには 2 つの ProvideValue
メソッドが含まれている必要があります。1 つは Color
を返し、もう 1 つは object
を返しますが、2 番目のメソッドは単に最初のメソッドを呼び出すだけで済みます。
[HSL Color Demo] (HSL カラー デモ) ページには、BoxView
の色を指定するために HslColorExtension
を XAML ファイルに表示するさまざまな方法が示されます。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.HslColorDemoPage"
Title="HSL Color Demo">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="WidthRequest" Value="80" />
<Setter Property="HeightRequest" Value="80" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<BoxView>
<BoxView.Color>
<local:HslColorExtension H="0" S="1" L="0.5" A="1" />
</BoxView.Color>
</BoxView>
<BoxView>
<BoxView.Color>
<local:HslColor H="0.33" S="1" L="0.5" />
</BoxView.Color>
</BoxView>
<BoxView Color="{local:HslColorExtension H=0.67, S=1, L=0.5}" />
<BoxView Color="{local:HslColor H=0, S=0, L=0.5}" />
<BoxView Color="{local:HslColor A=0.5}" />
</StackLayout>
</ContentPage>
HslColorExtension
が XML タグの場合、4 つのプロパティは属性として設定されますが、中かっこの間に表示される場合、4 つのプロパティは引用符なしでコンマで区切られます。 H
の既定値は S
、L
は 0、A
は 1 なので、既定値に設定する場合は、これらのプロパティを省略できます。 最後の例では、光度が 0 で、通常は黒になりますが、アルファ チャネルが 0.5 なので半分透明になり、ページの白い背景に対して灰色で表示されています。
ビットマップにアクセスするためのマークアップ拡張
ProvideValue
の引数は、.NET System
名前空間で定義されている IServiceProvider
インターフェイスを実装するオブジェクトです。 このインターフェイスには、1 つのメンバー、つまり、Type
引数を持つ GetService
という名前のメソッドがあります。
次に示す ImageResourceExtension
クラスは、特定のエラーが検出された場所を示す行と文字の情報を提供できる IXmlLineInfoProvider
オブジェクトを取得するための、IServiceProvider
と GetService
の 1 つの可能な使用法を示しています。 この場合、次に示すように、Source
プロパティが設定されていないと例外が発生します。
[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
public string Source { set; get; }
public ImageSource ProvideValue(IServiceProvider serviceProvider)
{
if (String.IsNullOrEmpty(Source))
{
IXmlLineInfoProvider lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
IXmlLineInfo lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
throw new XamlParseException("ImageResourceExtension requires Source property to be set", lineInfo);
}
string assemblyName = GetType().GetTypeInfo().Assembly.GetName().Name;
return ImageSource.FromResource(assemblyName + "." + Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<ImageSource>).ProvideValue(serviceProvider);
}
}
ImageResourceExtension
は、.NET Standard ライブラリ プロジェクトに埋め込みリソースとして保存されている画像ファイルに XAML ファイルがアクセスする必要がある場合に役立ちます。 これは、Source
プロパティを使用して静的 ImageSource.FromResource
メソッドを呼び出します。 このメソッドには、ピリオドで区切られたアセンブリ名、フォルダー名、ファイル名で構成される完全修飾リソース名が必要です。 ImageSource.FromResource
メソッドの 2 番目の引数はアセンブリ名を提供し、UWP 上のリリース ビルドにのみ必要になります。 ただし、それとは関係なく、ImageSource.FromResource
は、ビットマップを含むアセンブリから呼び出す必要があります。つまり、画像も外部ライブラリに存在しない限り、この XAML リソース拡張をそのライブラリに含めることはできません。 (埋め込みリソースとして保存されているビットマップへのアクセスに関する詳細については、「埋め込み画像」の記事を参照してください。)
ImageResourceExtension
では Source
プロパティを設定する必要がありますが、Source
プロパティは属性でクラスのコンテンツ プロパティとして示されます。 このことは、中かっこで囲まれた式の Source=
部分は省略できることを意味します。 [Image Resource Demo] (画像リソース デモ) ページでは、Image
要素は、ピリオドで区切られたフォルダー名とファイル名を使用して 2 つの画像をフェッチします。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.ImageResourceDemoPage"
Title="Image Resource Demo">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="{local:ImageResource Images.SeatedMonkey.jpg}"
Grid.Row="0" />
<Image Source="{local:ImageResource Images.FacePalm.jpg}"
Grid.Row="1" />
</Grid>
</ContentPage>
実行中のプログラムを次に示します。
サービス プロバイダー
ProvideValue
の IServiceProvider
引数を使用することにより、XAML マークアップ拡張は、それらが使用されている XAML ファイルに関する有用な情報にアクセスできます。 ただし、IServiceProvider
引数を正常に使用するには、特定のコンテキストで使用できるサービスの種類を把握する必要があります。 この機能を理解する最善の方法は、GitHub の Xamarin.Forms リポジトリの MarkupExtensions フォルダーにある既存の XAML マークアップ拡張のソース コードを調べることです。 いくつかの種類のサービスは、Xamarin.Forms の内部であることに注意してください。
一部の XAML マークアップ拡張では、このサービスが役立つ場合があります。
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
IProvideValueTarget
インターフェイスは 2 つのプロパティ、TargetObject
と TargetProperty
を定義します。 ImageResourceExtension
クラスでこの情報を取得する場合、TargetObject
は Image
であり、TargetProperty
は Image
の Source
プロパティの BindableProperty
オブジェクトです。 これは、XAML マークアップ拡張機能が設定されているプロパティです。
typeof(IProvideValueTarget)
の引数を使用した GetService
呼び出しは実際には、Xamarin.Forms.Xaml.Internals
名前空間で定義されている SimpleValueTargetProvider
型のオブジェクトを返します。 GetService
の戻り値をその型にキャストする場合、ParentObjects
プロパティにもアクセスできます。このプロパティは、Image
要素、Grid
親、Grid
の ImageResourceDemoPage
親を含む配列です。
まとめ
XAML マークアップ拡張は、さまざまなソースからの属性を設定する機能を拡張することで、XAML で重要な役割を果たします。 さらに、既存の XAML マークアップ拡張によって必要なものが正確に提供されない場合は、独自のものを記述することもできます。