Xamarin.Forms での実行時の XAML の読み込み

Xamarin.Forms.Xaml 名前空間には、実行時に XAML の読み込みと解析に使用できる 2 つの LoadFromXaml 拡張メソッドが含まれています。

背景

Xamarin.Forms XAML クラスが構築されると、LoadFromXaml メソッドが間接的に呼び出されます。 これは、XAML クラスのコードビハインド ファイルがコンストラクターから InitializeComponent メソッドを呼び出すために発生します。

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }
}

Visual Studio は、XAML ファイルを含むプロジェクトをビルドすると、XAML ファイルを解析して、たとえば MainPage.xaml.g.cs など、InitializeComponent メソッドの定義を含む C# コード ファイルを生成します。

private void InitializeComponent()
{
    global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
    ...
}

InitializeComponent メソッドは LoadFromXaml メソッドを呼び出して、.NET Standard ライブラリから XAML ファイル (またはそのコンパイル済みバイナリ) を抽出します。 抽出後は XAML ファイルで定義されているすべてのオブジェクトを初期化し、それらを親子関係で接続し、コードで定義されたイベント ハンドラーを XAML ファイルで設定されたイベントにアタッチし、結果として得られるオブジェクトのツリーをページのコンテンツとして設定します。

実行時の XAML の読み込み

LoadFromXaml メソッドは public なので、Xamarin.Forms アプリケーションから呼び出して読み込み、実行時に XAML を解析できます。 これにより、アプリケーションが Web サービスから XAML をダウンロードし、XAML から必要なビューを作成してアプリケーションに表示するなどのシナリオが可能になります。

警告

ランタイム時の XAML の読み込みはパフォーマンス コストが大きく、通常は避ける必要があります。

次のコードは、簡単な使用例を示しています。

using Xamarin.Forms.Xaml;
...

string navigationButtonXAML = "<Button Text=\"Navigate\" />";
Button navigationButton = new Button().LoadFromXaml(navigationButtonXAML);
...
_stackLayout.Children.Add(navigationButton);

この例では、Button インスタンスが作成され、その Text プロパティ値が、string で定義されている XAML から設定されます。 その後、Button が、ページの XAML で定義されている StackLayout に追加されます。

LoadFromXaml拡張メソッドを使用すると、ジェネリック型引数を指定できます。 ただし、操作対象のインスタンスの型から推論されるため、型引数を指定する必要はほとんどありません。

この LoadFromXaml メソッドを使用すると、任意の XAML を拡張できます。次の例では、ContentPage を拡張してから、それに移動します。

using Xamarin.Forms.Xaml;
...

// See the sample for the full XAML string
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n</ContentPage>";

ContentPage page = new ContentPage().LoadFromXaml(pageXAML);
await Navigation.PushAsync(page);

要素へのアクセス

LoadFromXaml メソッドを使用して実行時に XAML を読み込む場合、(x:Name を使用して) ランタイム オブジェクト名を指定した XAML 要素への厳密に型指定されたアクセスは許可されません。 ただし、これらの XAML 要素は FindByName メソッドを使用して取得し、必要に応じてアクセスできます。

// See the sample for the full XAML string
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n<StackLayout>\n<Label x:Name=\"monkeyName\"\n />\n</StackLayout>\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);

Label monkeyLabel = page.FindByName<Label>("monkeyName");
monkeyLabel.Text = "Seated Monkey";
...

この例では、ContentPage の XAML が拡張されています。 この XAML には、monkeyName という名前の Label が含まれています。これは、Textプロパティが設定される前に FindByName メソッドを使用して取得されます。