XAML マークアップ拡張
- 10 分
XAML 定義の多くは、コンパイル時に決定されます。 多くの場合、要素を配置する場所、使用する色とフォント、プロパティに割り当てるリテラル値はわかります。
ただし、時には、コンパイル時に決定できない値をプロパティ値に設定する場合もあります。 これらの値は、プログラム実行中のみわかります。 このような状況では、実行時に XAML に値を指定するオブジェクトを作成できます。 XAML では、この目的で マークアップ拡張機能 がサポートされています。
このユニットでは、マークアップ拡張を作成して使用する方法について説明します。
マークアップ拡張とは
マークアップ拡張は、ランタイムの値にアクセスするために XAML で使うクラスです。 XAML UI で多くのラベルが定義されており、すべてのラベルのスタイルが一貫するように、アプリ全体で FontSize プロパティを同じ値に設定したいとします。 FontSize プロパティは、次に示すように、XAML を使って設定できます。
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="28"
HorizontalOptions="CenterAndExpand"/>
この同じ設定をすべてのラベルに対して繰り返すことができますが、後でこの値を変更する場合はどうなるでしょうか。 このプロパティのすべてのインスタンスを見つけ、変更する必要があります。 また、どのような値を使うとよいか決められない場合を考えてください。デバイスの向きや画面の解像度、その他の考慮事項などの要因に基づいて実行時に計算される可能性もあります。 このような場合、ハードコーディングされたリテラルよりも高度なものが必要です。 そこで、マークアップ拡張が役に立ちます。 マークアップ拡張を使用すると、XAML で使用される値を取得する方法に柔軟性がもたらされます。
マークアップ拡張を作成する
マークアップ拡張機能は、 Microsoft.Maui.Controls.Xaml.IMarkupExtension インターフェイスを実装するクラスです。 このインターフェイスでは、次のシグネチャを持つ ProvideValue という 1 つのメソッドが定義されています。
public object ProvideValue(IServiceProvider serviceProvider)
{
...
}
このメソッドの目的は、XAML マークアップに値を指定することです。 戻り値の型が object であることに注意してください。そのため、適切な場所で値が使われている限り、値を任意の型にすることができます。 たとえば、フォント サイズを計算して返すマークアップ拡張では、戻り値の型は double にします。
serviceProvider パラメーターには、XAML コード内でマークアップ拡張が使われている場所に関するコンテキスト情報が含まれています。その他の情報としては、それは拡張機能が適用されているコントロールを識別します。
FontSize プロパティのマークアップ拡張は単純な状態に維持できます。 次の例の MainPage クラスでは、MyFontSize という名前の double フィールドが公開されています。 GlobalFontSizeExtension クラスは IMarkupExtension インターフェイスを実装しており、ProvideValue メソッドは MyFontSize 変数の値を返します。
namespace MyMauiApp;
public partial class MainPage : ContentPage
{
public const double MyFontSize = 28;
public MainPage()
{
InitializeComponent();
...
}
...
}
public class GlobalFontSizeExtension : IMarkupExtension
{
public object ProvideValue(IServiceProvider serviceProvider)
{
return MainPage.MyFontSize;
}
}
注
ProvideValue メソッド内で MyFontSize フィールドをこの方法で参照できるためには、フィールドが MainPage クラスの static メンバーである必要があります。 適切な方法は、この場合、変数も定数であることです。 const の値は static です。
ProvideValue メソッドでは、方向とデバイスのフォーム ファクターに応じて、返される値を調整することもできます。
XAML のコントロールにマークアップ拡張を適用する
XAML コードでマークアップ拡張を使うには、GlobalFontSizeExtension クラスを含む名前空間を ContentPage タグの名前空間のリストに追加します。 次の例では、この名前空間にエイリアス mycode が指定されています。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mycode="clr-namespace:MyMauiApp"
x:Class="MyMauiApp.MainPage">
マークアップ拡張を使用すると、このように FontSize プロパティを設定できます。 この規則では、マークアップ拡張機能の名前にサフィックス Extension が含まれている点に注意してください。 XAML はこのサフィックスを認識し、XAML コードから拡張機能を呼び出すときにサフィックスを含める必要はありません。 次の例の GlobalFontSizeExtension クラスは、単に GlobalFontSize として参照されています。
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="{mycode:GlobalFontSize}"
HorizontalOptions="CenterAndExpand"/>
フォント サイズを指定する必要があるすべてのコントロールに対して、XAML コード全体で同じマークアップ拡張を適用できます。 後で、フォント サイズを変更する場合は、MyFontSize 変数の定義を MainPage クラスで変更するだけで済みます。
StaticExtension クラス
GlobalFontSize マークアップ拡張と同様に便利ですが、このような拡張を作成することはあまりありません。 その理由は簡単で、.NET MAUI にはより一般化された拡張機能が既にあり、コード内のあらゆる静的な値を参照できるからです。 この拡張機能は、StaticExtension または略して Static という名前です。 次のコードは、この拡張クラスの基本的な概要を示しています。
[ContentProperty ("Member")]
public class StaticExtension : IMarkupExtension
{
public string Member {get; set;}
public object ProvideValue (IServiceProvider serviceProvider)
{
...
}
}
注
カスタム マークアップ拡張の目的は、単純な静的ケースよりも複雑な状況に対処できるようにすることです。 たとえば、デバイスのフォーム ファクターに基づいてフォント サイズを動的に変更することが必要な場合があります。
XAML コードでこのクラスを使うには、Member プロパティで参照したい静的変数の名前を指定すると、ProvideValue メソッドからこの変数の値が返ります。 次の例は、その使い方を示します。
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="{x:Static Member=mycode:MainPage.MyFontSize}"
HorizontalOptions="CenterAndExpand"/>
.NET MAUI には、データ バインディング、動的リソースとスタイルの参照、データの配列の処理などのシナリオに使用できる、他のマークアップ拡張クラスのセットが用意されています。