XAML の使用を開始する

Browse sample. サンプルを参照する

.NET マルチプラットフォーム アプリ UI (.NET MAUI) アプリでは、XAML は主にページのビジュアル コンテンツを定義するために使用され、C# コードビハインド ファイルと連携します。 コードビハインド ファイルは、マークアップのコード サポートを提供します。 これら 2 つのファイルは、子ビューとプロパティの初期化を含む新しいクラス定義に貢献します。 XAML ファイル内では、クラスとプロパティは XML 要素と属性で参照され、マークアップとコード間のリンクが確立されます。

XAML ファイルの構造

新しい .NET MAUI アプリには、3 つの XAML ファイルとそれに関連するコードビハインド ファイルが含まれています。

Screenshot of the structure of a new .NET MAUI app.

最初のファイル ペアリングは、App.xaml (XAML ファイル) と App.xaml.cs (XAML ファイルに関連のある C# コードビハインド ファイル)です。 App.xamlApp.xaml.cs は両方とも、Applicationから派生した App という名前のクラスに貢献します。 2 番目のファイル ペアリングは、AppShell.xamlAppShell.xaml.cs です。これは、Shell から派生した AppShell という名前のクラスに貢献します。 XAML ファイルのある他のほとんどのクラスは、ContentPage から派生するクラスに貢献し、ページの UI を定義します。 これは、MainPage.xaml および MainPage.xaml.cs ファイルに当てはまります。

MainPage.xaml ファイルの構造は次のとおりです。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyMauiApp.MainPage">
    ...
</ContentPage>

2 つの XML 名前空間 (xmlns) 宣言は、microsoft.com の URI を参照します。 ただし、これらの URI にコンテンツはなく、基本的にバージョン識別子として機能します。

最初の XML 名前空間宣言は、プレフィックスのない XAML ファイル内で定義されたタグが、.NET MAUI のクラスを参照することを意味します (たとえば、ContentPage)。 2 番目の名前空間宣言では、x のプレフィックスを定義します。 これは、XAML 自体に組み込まれ、XAML の他の実装でサポートされている複数の要素と属性で使用されます。 ただし、これらの要素と属性は、URI に埋め込まれた年によって若干異なります。 .NET MAUI では、2009 XAML 仕様がサポートされています。

最初のタグの末尾で、x プレフィックスが名前付きの Class属性に使用されます。 この x プレフィックスの使用は XAML 名前空間で実質的に汎用なので、Class のような XAML 属性はほとんどの場合、x:Class として参照されます。 x:Class 属性は、完全修飾 .NET クラス名 (MyMauiApp 名前空間の MainPage クラス) を指定します。 つまり、この XAML ファイルは、ContentPage (x:Class 属性が現れるタグ) から派生する MyMauiApp 名前空間で MainPage という名前の新しいクラスを定義します。

x:Class 属性は、派生した C# クラスを定義するために XAML ファイルのルート要素にのみ表示できます。 これは、XAML ファイルで定義されている唯一の新しいクラスです。 XAML ファイルに表示される他のものはすべて、既存のクラスからインスタンス化され、初期化されます。

MainPage.xaml.cs ファイルは次のようになります。

namespace MyMauiApp;

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

MainPage クラスはContentPage から派生し、部分的なクラスの定義です。

Visual Studio がプロジェクトをビルドすると、ソース ジェネレーターによって、MainPageコンストラクターから呼び出される InitializeComponent メソッドの定義を含む新しい C# ソースが生成され、コンパイル オブジェクトに追加されます。

ランタイム時に、MauiProgram クラスのコードによってアプリがブートストラップされ、App クラス コンストラクターが実行され、AppShell がインスタンス化されます。 AppShell クラスは、表示 されるアプリの最初のページをインスタンス化します (MainPage)。 MainPage コンストラクターは InitializeComponent を呼び出します。これにより、XAML ファイルで定義されているすべてのオブジェクトを初期化し、それらをすべて親子関係で接続し、コードで定義されたイベント ハンドラーを XAML ファイルで設定されたイベントに添付し、その結果生じるオブジェクト ツリーをページのコンテンツとして設定します。

AppShell クラスでは、.NET MAUI シェルを使用して、表示するアプリの最初のページを設定します。 ただし、シェルは、この XAML 概要の範疇ではありません。 詳細については、「.NET MAUI シェル」を参照してください。

ページ コンテンツを設定する

ContentPage には 1 つの子が含まれている必要があります。これは、ビューまたは子ビューを含むレイアウトにすることができます。 ContentPage の子は、ContentPage.Content プロパティの値として自動的に設定されます。

次の例は、Label が含まれている ContentPage です:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page">
    <Label Text="Hello, XAML!"
           VerticalOptions="Center"
           HorizontalTextAlignment="Center"
           Rotation="-15"
           FontSize="18"
           FontAttributes="Bold"
           TextColor="Blue" />
</ContentPage>

上記の例では、クラス、プロパティ、および XML の関係が明らかです。 .NET MAUI クラス (Label または ContentPage など) は、XML 要素として XAML ファイルに表示されます。 通常、そのクラスのプロパティ (ContentPageTitleLabel の 7 個のプロパティを含む) は XML 属性として表示されます。

これらのプロパティの値を設定するための多くのショートカットが存在します。 一部のプロパティは基本的なデータ型です。 たとえば、TitleText プロパティは string 型、Rotationdouble 型です。 HorizontalTextAlignment プロパティは TextAlignment 型 (列挙型) です。 任意の列挙型のプロパティの場合、指定する必要があるのはメンバー名のみです。

ただし、より複雑な型のプロパティの場合は、XAML の解析にコンバーターが使用されます。 これらは TypeConverter から派生した .NET MAUI のクラスです。 上記の例では、文字列値を正しい型に変換するために、複数の .NET MAUI コンバーターが自動的に適用されます:

  • VerticalOptions プロパティの LayoutOptionsConverter。 このコンバーターは、LayoutOptions 構造の公開用静的フィールドの名前を LayoutOptions 型の値に変換します。
  • TextColor プロパティの ColorTypeConverter。 このコンバーターは、アルファ チャネルの有無にかかわらず、Colors クラスまたは 16 進数の RGB 値の公開用静的フィールドの名前を変換します。

.NET MAUI アプリを実行すると、通常は MainPage が表示されます。 別のページを表示するには、AppShell.xaml ファイルで新しいスタートアップ ページとして設定するか、MainPage から新しいページに移動できます。

ナビゲーションを実装するには、MainPage.xaml.cs コンストラクターでシンプルな Button を作成し、イベント ハンドラーを使って HelloXamlPage に移動できます:

public MainPage()
{
    InitializeComponent();

    Button button = new Button
    {
        Text = "Navigate!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

    button.Clicked += async (sender, args) =>
    {
        await Navigation.PushAsync(new HelloXamlPage());
    };

    Content = button;
}

このアプリの新しいバージョンをコンパイルして展開すると、画面にボタンが表示されます。 これを押すと、HelloXamlPage に移動します:

Screenshot of rotated Label text.

各プラットフォームに表示されるナビゲーションバーを使用して、MainPage に戻ることができます。

このナビゲーション モデルの代わりに、.NET MAUI シェルを使用できます。 詳細については、「.NET MAUI シェルの概要」を参照してください。

XAML とコードの相互作用

ほとんどの ContentPage 派生物の子は、StackLayoutGrid などのレイアウトで、レイアウトには複数の子を含めることができます。 XAML では、親子関係が通常の XML 階層で確立されます:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="Center" />
        <Label Text="A simple Label"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="Center" />
    </StackLayout>
</ContentPage>

この XAML ファイルは構文的に完全であり、次の UI が生成されます:

Screenshot of multiple controls on a page.

ただし、SliderButton を操作することはできますが、UI は更新されません。 Slider によって Label には現在の値が表示され、Button が動作を行うはずです。

Label を使用した Slider 値の表示は、データ バインディングを使って完全に XAML で実行できます。 ただし、最初にコード ソリューションを確認すると便利です。 それでも、Button クリックを処理するには間違いなくコードが必要です。 つまり、XamlPlusCodePage のコードビハインド ファイルには、SliderValueChanged イベントと ButtonClicked イベントのハンドラーを含める必要があります:

namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {
            valueLabel.Text = args.NewValue.ToString("F3");
        }

        async void OnButtonClicked(object sender, EventArgs args)
        {
            Button button = (Button)sender;
            await DisplayAlert("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
        }
    }
}

XAML ファイルに戻り、Slider および Button タグには、これらのハンドラーを参照する ValueChangedClicked イベントの属性を含めなくてはなりません。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="Center"
                ValueChanged="OnSliderValueChanged" />
        <Label x:Name="valueLabel"
               Text="A simple Label"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Clicked="OnButtonClicked" />
    </StackLayout>
</ContentPage>

イベントにハンドラーを割り当てる構文は、プロパティに値を割り当てる場合と同じ構文であることに注意してください。 さらに、SliderValueChanged イベント ハンドラーが Label を使用して現在の値を表示するには、ハンドラーがそのオブジェクトをコードから参照する必要があります。 そのため、Label には、x:Name 属性で指定される名前が必要です。 x:Name 属性の x のプレフィックスは、この属性が XAML に組み込まれていることを示します。 x:Name 属性に割り当てる名前には、C# 変数名と同じ規則があります。 たとえば、文字またはアンダースコアで始まり、スペースを埋め込まないなどです。

ValueChanged イベント ハンドラーは、イベント引数から使用できる新しい Slider 値を表示するように Label をできるようになりました。

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

また、ハンドラーは、sender引数からこのイベントを生成する Slider オブジェクトを取得し、そこから Value プロパティを取得できます。

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

その結果、Slider の操作を行うと、その値が Label に表示されます:

Screenshot of multiple controls on a page, with Slider value displayed.

上記の例では、ボタンの Text でアラートを表示してButtonClicked イベントへの応答をシミュレートしています。 そのため、イベント ハンドラーは sender 引数を Button にキャストし、そのプロパティにアクセスできます。

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
}

OnButtonClicked メソッドは async として定義されます。DisplayAlert メソッドは非同期で、メソッドの完了時に返される await 演算子で始まる必要があるためです。 このメソッドは sender 引数からイベントを発生させる Button を取得するため、複数のボタンで同じハンドラーを使用できます。

次のステップ

XAML は、主にオブジェクトのインスタンス化と初期化を目的として設計されています。 ただし、多くの場合、プロパティは XML 文字列として簡単に表現できない複合オブジェクトに設定する必要があり、1 つのクラスで定義されたプロパティを子クラスに設定する必要があります。 この 2 つでは、プロパティ要素添付プロパティの基本的な XAML 構文機能が必要です。