パート 1. XAML 入門

 

パート 1. XAML 入門

ページの要素と属性の定義

Xamarin.Forms アプリケーションでは、XAML はページのビジュアル コンテンツを定義するために使用されます。XAML ファイルは、マークアップのコード サポートを行う C# コード ファイルと常に関連しています。これらの 2 つのファイルには、子のビューとプロパティの初期化を含む新しいクラス定義が含まれます。XAML ファイル内では、クラスとプロパティは XML 要素と属性で参照され、マークアップとコード間のリンクが確立されます。

 

ページの作成

最初の XAML ファイルの編集を開始するには、Visual Studio または Xamarin Studio を使用して、新しい Xamarin.Forms ソリューションを作成します。

Visual Studio:

Visual Studio で、メニューから [File] > [New] > [Project] を選択します。[New Project] ダイアログで、左の [Visual C#] > [Mobile Apps] を選択した後、中央のリストから Blank App (Xamarin.Forms Portable) を選択します。このオプションは、XAML をサポートする PCL ベースのソリューションを作成します。

Xamarin Studio:

Xamarin Studio で、メニューから [File] > [New] > [Solution] を選択します。[New Solution] ダイアログで、左の [Cross Platform] > [App] を選択した後、テンプレート リストから Blank Xamarin.Forms App を選択します。

次の画面で、Xamarin.Forms アプリケーションの名前を付けて、共有コード オプションで **Use Portable Class Library** を選択します。このオプションは、XAML をサポートする PCL ベースのソリューションを作成します。

ソリューションの場所を選択して名前を XamlSamples (またはほかの名前) にします。

Visual Studio は、4 つのプロジェクト (XamlSamples.Android、XamlSamples.iOS、XamlSamples.WinPhone、および共有 Portable Class Library (PCL) プロジェクト XamlSamples) を作成します。

PC 上で Xamarin Studio を使用している場合は、XamlSamples.Android プロジェクトと XamlSamples プロジェクトのみ作成します。Mac 上で Xamarin Studio を使用している場合は、XamlSamples.iOS プロジェクトも作成します。

Xamarin.Forms ソリューションを作成したら、開発環境をテストします。ソリューションのスタートアップ プロジェクトとしてさまざまなプラットフォーム プロジェクトを選択し、携帯エミュレーターまたは実デバイスのいずれかのプロジェクト テンプレートを使用して、単純なアプリケーションをビルドして展開します。

プラットフォーム固有のコードを記述する必要がなければ、共有 XamlSamples PCL プロジェクトが、事実上プログラミング時間のすべてを費やす場所となります。この記事では、このプロジェクトのみ取り上げます。

XAML は、Xamarin.Forms アプリケーションでさまざまな役割を果たすことができますが、最も一般的なのは、ページ全体のビジュアル コンテンツ (通常は、ContentPage から派生したクラス) を定義することです。

では、XAML ベースの ContentPage を XamlSamples プロジェクトに追加しましょう。

Visual Studio:

Visual Studio で、XamlSamples プロジェクトを右クリックして [Add] > [New Item] を選択します。[Add New Item] ダイアログで、左の [Visual C#] > [Code] を選択した後、リストから Forms Xaml Page を選択します。

Xamarin Studio:

Xamarin Studio で、[XamlSamples] ドロップダウン メニューから、[Add] > [New File] を選択します。[New File] ダイアログで、左の [Forms] を選択した後、リストから (Forms ContentView Xaml ではなく) Forms ContentPage Xaml を選択します。

名前を HelloXamlPage にします。

2 つのファイルが XamlSamples プロジェクトに作成されます。1 つ目のファイルは XAML ファイルで、名前は HelloXamlPage.xaml です。2 つ目のファイルはその下に表示されます。C# コード ファイルで、名前は HelloXamlPage.xaml.cs です。これらの 2 つのファイルの名前は、それらが詳細に関連付けられていることを示します。C# ファイルは、XAML ファイルの 分離コード ファイルと呼ばれることもあります。

HelloXamlPage.xamlHelloXamlPage.xaml.cs はどちらも、ContentPage から派生したクラス HelloXamlPage の定義に役立っています。

 

XAML クラスの中身

HelloXamlPage.xaml で最初に行うことは、開始タグと終了タグの間の行をすべて削除することです。ファイルは次のようになります。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage">
</ContentPage>

2 つの XML 名前空間 (xmlns) 宣言は、URI を参照しています。1 つ目の URI は Xamarin の Web サイトを、2 つ目の URI は Microsoft の Web サイトを指しています。これらの URI が何を指しているかわざわざ確認する必要はありません。その先には何もありません。これらは Xamarin と Microsoft により所有されている単なる URI で、基本的にバージョン ID として機能します。

1 つ目の XML 名前空間宣言は、接頭辞のない XAML ファイル内で定義されたタグが Xamarin.Forms のクラス (例えば、ContentPage) を指すことを意味します。2 つ目の名前空間宣言は、x の接頭辞を定義します。これは、XAML 固有の、(理論上) XAML のすべての実装でサポートされる要素と属性に使用されます。しかし、これらの要素と属性は URI で指定されている年によって多少異なります。Xamarin.Forms は、2009 XAML 仕様をサポートしています (一部を除く)。

x 接頭辞が宣言された直後に、その接頭辞は Class の属性に使用されます。この x 接頭辞は XAML ファイルではほぼ全般的に使用されるため、Class のような XAML 属性は常に x:Class と呼ばれます。

x:Class 属性は完全に修飾された .NET クラス名 (XamlSamples 名前空間の HelloXamlPage クラス) を指定します。これは、この XAML ファイルが ContentPage (x:Class 属性が現れるタグ) から派生する XamlSamples 名前空間の新しいクラス HelloXamlPage を定義することを意味します。

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

HelloXamlPage.xaml.cs 分離コード ファイルは次のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

partial クラス定義に注意してください。このクラス定義では明示的に示されていませんが、HelloXamlPageContentPage から派生します。

しかし、何か見当たらないものがあります。HelloXamlPage の別の部分的なクラス定義を含む別の C# ファイルがあるはずです。また、InitializeComponent メソッドは何でしょうか。これから説明します。

XamlSamples プロジェクトの App クラスを見ると、既存のコードの一部を削除し、App コンストラクターを使用して HelloXamlPage のインスタンスに MainPage をセットすればいいことが分かります。

namespace XamlSamples
{
    public class App : Xamarin.Forms.Application
    {
        public App ()
        {
            MainPage = new HelloXamlPage();
        }
    }
}

プロジェクトは、3 つのプラットフォームのすべてでコンパイルできるようになりましたが、ページは空です。

ビルド-展開-実行サイクル中に、XAML ファイルは 2 回解析されます。まず、ビルド プロセス中に最初に解析されます。XAML ファイル全体は Portable Code Library DLL にバインドされ、ランタイムに再び解析されます。

ビルド ステップ中に、C# コード ファイルが XAML ファイルから生成されます。XamlSamples\XamlSamples\obj\Debug ディレクトリを参照すると、HelloXamlPage.xaml.g.cs という名前のファイルが見つかります。‘g’ は生成されたことを表します。このファイルを次に示します (ファイルを変更すべきでないことを示すコメントは含まれていません)。

namespace XamlSamples {
    using System;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;

    public partial class HelloXamlPage : ContentPage {

        private void InitializeComponent() {
            this.LoadFromXaml(typeof(HelloXamlPage));
        }
    }
}

これは HelloXamlPage の別の部分的なクラス定義で、基底クラスが ContentPage であることを明示的に示しています。このクラス定義は、HelloXamlPage コンストラクターから呼び出された InitializeComponent メソッドの定義も含んでいます。ビルド プロセス中に、このコードが XAML ファイルから最初に生成された後、HelloXamlPage の 2 つの部分的なクラス定義が一緒にコンパイルされます。

ランタイムに、特定のプラットフォーム オブジェクトのコードはスタティック App.GetMainPage メソッドを呼び出して初期ページを取得します。このメソッドは HelloXamlPage をインスタンス化します。そのクラスのコンストラクターは InitializeComponent を呼び出します。次に、Portable Class Library から XAML ファイル全体を抽出して解析する LoadFromXaml メソッドを呼び出し、XAML ファイルで定義されているオブジェクトをすべてインスタンス化および初期化し、それらを親-子関係ですべて接続し、コードで定義されたイベント ハンドラーを XAML ファイルのイベント セットにアタッチし、オブジェクトの結果ツリーをページのコンテンツとしてセットします。

通常、生成されたコード ファイルに多くの時間を費やす必要はありませんが、生成されたファイルのコードでランタイム例外が発生することがあるため、これらの例外についてよく理解する必要があります。

ビルド プロセス中の XAML ファイルの解析は、ランタイムの後の解析と比較すると基本的です。ビルド時の解析で XML 構文エラーは分かりますが、要素や属性のスペルの間違いは分かりません。その種の問題はランタイムで検出されます。幸い、ランタイム例外は通常、問題を発見して解決するための十分な情報を提供します。

Xamarin Studio は、例外メッセージをポップアップ ウィンドウで表示します。Visual Studio で、iOS や Android アプリケーションを実行している場合、XAML 例外は LoadFromXaml 呼び出しで生成されるコード ファイルに含まれます。Xamarin.Forms.Xaml.XamlParseException 型の Instance オブジェクトの Local ウィンドウを確認します。Message プロパティは、通常、行番号と列番号に関する問題を示します。この情報を取得するには内部の例外を確認する必要があります。

Windows Phone 上でプログラムを実行したときに XAML 例外が発生すると、App.xaml.cs ファイルの RootFrame_NavigationFailed が呼び出されます。$exception オブジェクトはこの問題を示します。

 

ページ コンテンツの設定

単一ページの Xamarin.Forms アプリケーションは、通常、ContentPage の派生クラスを含んでいます。このクラスの Content プロパティは、一般に単一ビューまたは子ビューを含むレイアウトに設定されます。XAML では、開始および終了 ContentPage タグ間に配置することにより、ビュー (例えば、Label) をページの Content プロパティに暗黙的に設定することができます。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page"
             Padding="10, 40, 10, 10">

  <Label Text="Hello, XAML!"
         VerticalOptions="Start"
         HorizontalTextAlignment="Center"
         Rotation="-15"
         IsVisible="true"
         FontSize="Large"
         FontAttributes="Bold"
         TextColor="Aqua" />

</ContentPage>

この時点で、クラス、プロパティ、XML 間の関係は明白であるべきです。Xamarin.Forms クラス (ContentPageLabel など) は XAML ファイルに XML 要素として現れ、そのクラスのプロパティ (ContentPageTitlePadding および Label の 7 つのプロパティを含む) は XML 属性として現れます。

これらのプロパティの値を設定する多くのショートカットが存在します。一部のプロパティは基本的なデータ型です。例えば、Title および Text プロパティは String 型、Rotation プロパティは Double 型、IsVisible (デフォルトで true ですが、ここでは説明のために設定しています) プロパティは Boolean 型です。

HorizontalTextAlignment プロパティは TextAlignment (列挙) 型です。列挙型のプロパティでは、提供する必要があるのはメンバー名のみです。

しかし、より複雑な型のプロパティでは、XAML の解析にコンバーターが使用されます。これらは TypeConverter から派生する Xamarin.Forms のクラスです ほとんどはパブリック クラスですが、一部は違います。特にこの XAML ファイルでは、次のようなクラスが舞台裏でその役割を果たしています。

  • Padding プロパティの ThicknessTypeConverter
  • VerticalOptions プロパティの LayoutOptionsConverter
  • FontSize プロパティの FontSizeConverter
  • TextColor プロパティの ColorTypeConverter

これらのコンバーターは、可能なプロパティ設定の構文を管理します。

ThicknessTypeConverter は、カンマで区切られた 1 つ、2 つ、または 4 つの数を処理します。1 つの数が提供された場合、その数が上下左右すべてに適用されます。2 つの数の場合、最初の数が左右、次の数が上下に適用されます。4 つの数の場合、順に、左、上、右、下に適用されます。

LayoutOptionsConverter は、LayoutOptions 構造のパブリック スタティック フィールドの名前を LayoutOptions 型の値に変換します。

FontSizeConverter は、NamedSize メンバーまたは数値フォント サイズを処理します。

ColorTypeConverter は、Color 構造のパブリック スタティック フィールドの名前または 16 進の RGB 値 (アルファ チャネルあり/なし、先頭が # 記号) を処理します。アルファ チャネルなしの構文は次のようになります。

TextColor="#rrggbb"

小文字はそれぞれ、16 進数です。アルファ チャネルを含めると次のようになります。

TextColor="#aarrggbb"

アルファ チャネルは、FF が完全に不透明、00 が完全に透明であることに注意してください。

他の 2 つのフォーマットで、各チャネルの 1 つの 16 進の桁を指定できます。

TextColor="#rgb" TextColor="#argb"

この場合、桁が繰り返されます。例えば、#CF3 は RGB カラー CC-FF-33 になります。

iPhone、Android、および Windows Phone で表示した結果を次に示します。

Unicode 文字をテキストに埋め込む必要がある場合は、標準 XML 構文を使用します。例えば、テキストを引用符で囲むには、次のように指定します。

<Label Text="&amp;#x201C;Hello, XAML!&amp;#x201D;" … />

結果は次のようになります。

これらのスクリーンショットは、App.GetMainPage メソッドから HelloXamlPage を直接インスタンス化してリターンした場合の結果です。ダウンロード可能な XamlSamples ソリューションには、XAML に関する一連の記事のサンプル XAML がすべて含まれています。プログラム中の HelloXamlPage は、ナビゲーション アーキテクチャの違いにより、iPhone と Android で多少異なっています。この記事の残りのスクリーンショットは、ダウンロード可能な XamlSamples ソリューションから直接撮影したもので、iPhone と Android の上部にナビゲーション ユーザー インターフェイスが表示されています。

 

XAML とコードの対話処理

HelloXamlPage サンプルにはページに 1 つの Label しか含まれていませんが、これは非常に稀な例です。ほとんどの ContentPage の派生クラスは、Content プロパティを設定して StackLayout などのレイアウトを行っています。StackLayoutChildren プロパティは IList<View> 型で定義されますが、実際には ElementCollection<View> 型のオブジェクトであり、そのコレクションには複数のビューや他のレイアウトを含めることができます。XAML では、これらの親-子関係は通常の XML 階層で確立されます。XamlPlusCodePage クラスの XAML ファイルを次に示します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
  <StackLayout>
    <Slider VerticalOptions="CenterAndExpand" />

    <Label Text="A simple Label"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

    <Button Text="Click Me!"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" />
  </StackLayout>
</ContentPage>

この XAML ファイルは構文的には問題ありません。

ただし、機能は不足しているようです。Slider を操作すると Label に現在値が表示され、Button はプログラム内の何かを実行するように意図されています。

パート 4. データ バインディングの基本で説明しているように、Label を使用して Slider 値を表示する操作は、データ バインディングにより XAML ですべて処理することができます。しかし、コード ソリューションを最初に見ておくことは後で役に立ちます。Button のクリックを制御するにはコードを追加する必要があります。これは、XamlPlusCodePage の分離コード ファイルに SliderValueChanged イベントと ButtonClicked イベントのハンドラーを含める必要があることを意味します。では、ハンドラーを追加しましょう。

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

        void OnSliderValueChanged(object sender,
                                  ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

これらのイベント ハンドラーはパブリックである必要はありません。

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

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
  <StackLayout>
    <Slider VerticalOptions="CenterAndExpand"
            ValueChanged="OnSliderValueChanged" />

    <Label Text="A simple Label"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

    <Button Text="Click Me!"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand"
            Clicked="OnButtonClicked" />
  </StackLayout>
</ContentPage>

イベントへのハンドラーを割り当てる構文は、プロパティに値を割り当てる構文と同じです。

SliderValueChanged イベントのハンドラーが Label を使用して現在値を表示している場合、ハンドラーはコードのオブジェクトを参照する必要があります。Label は、x:Name 属性で指定された名前が必要です。

<Label x:Name="valueLabel"
       Text="A simple Label"
       Font="Large"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />

x:Name 属性の x 接頭辞は、この属性が XAML 固有であることを示します。

x:Name 属性に割り当てる名前の規則は C# の変数名と同じです。例えば、文字または下線で始まり、途中にスペースは使用しません。

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

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

あるいは、ハンドラーは、送り側の引数からこのイベントを生成している Slider オブジェクトを取得して、Value プロパティを取得することができます。

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

最初にプログラムを実行したとき、ValueChanged イベントはまだ送られていないため、LabelSlider 値を表示しません。しかし、Slider を操作すると、値が表示されます。

次は Button の処理です。ボタンの Text を含むメッセージを表示して、Clicked イベントの応答をシミュレートします。イベント ハンドラーは 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");
}

DisplayAlert メソッドは非同期であるため、メソッドは async で定義し、メソッドが完了したときにリターンするように、await 演算子を使用します。このメソッドは sender 引数からイベントを送る Button を取得しているため、同じハンドラーを複数のボタンに使用することもできます。

ここでは、XAML で定義されたオブジェクトは分離コード ファイルで制御されるイベントを送ることができること、分離コード ファイルは x:Name 属性で割り当てられた名前を使用して XAML で定義されたオブジェクトにアクセスできることを示しました。これらは XAML とコードの対話処理を行う 2 つの基本的な方法です。

x:Name 属性に割り当てられた名前をプライベート フィールドとして含む、新しく生成された XamlPlusCode.xaml.g.cs ファイルを調べることにより、XAML の動作について追加の洞察を得ることができます。

public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

    private void InitializeComponent() {
        this.LoadFromXaml(typeof(XamlPlusCodePage));
        valueLabel = this.FindByName<Label>("valueLabel");
    }
}

このフィールドの宣言により、XamlPlusCodePage 部分クラス ファイル内の任意の場所で変数を自由に使用することができます。ランタイムに、フィールドは、XAML が解析された後に割り当てられます。つまり、valueLabel フィールドは XamlPlusCodePage コンストラクターが開始するときは null ですが、InitializeComponent が呼び出された後は有効になります。

InitializeComponent がコンストラクターに制御を返した後、あたかもコードでインスタンス化および初期化されたかのように、ページのビジュアル部分が作成されます。XAML ファイルは、もはやクラスでの役割を果たしていません。例えば、StackLayout にビューを追加したり、全体にページの Content プロパティを設定することにより、任意の方法でページのオブジェクトを操作することができます。ページの Content プロパティおよびレイアウトの Children コレクションのアイテムを調べることにより、「ツリーを探索する」ことができます。この方法でアクセスされたビューのプロパティを設定したり、イベント ハンドラーを動的に割り当てることもできます。

自分のページで自由に処理を行ってください。XAML はコンテンツを作成するツールに過ぎません。

 

まとめ

ここでは、初期化を含む新しいクラス定義における XAML ファイルとコード ファイルの役割、XAML とコード ファイルの対話方法について説明しました。XAML には、非常に柔軟な方法で使用できる、独特の構文機能があります。この続きは、パート 2. 基本的な XAML 構文で説明します。

 

 


Infragistics Infragistics
エンタープライズ向け統合 UI 開発コンポーネント。WinForms、モバイル、Web 用の UI コントロール。
CData ドライバー CData ドライバー
50 以上のデータ ソースへのアクセスをプログラミングなしで可能にするデータベース ドライバー。
SmartBear Software SmartBear
GUI テスト / プロファイラー / 負荷テスト / API テスト: ソフトウェア テストの自動化/工数削減/品質向上。
/n software IP*Works! /n software IP*Works!
クロスプラットフォーム対応のインターネット アプリケーション開発向けコンポーネント スイート。
UXDivers Grial UI Kit
Xamarin Forms 対応の XAML ベースの UI、UX テンプレートを提供
XFINIUM.PDF XFINIUM.PDF
Xamarin 対応のクロスプラットフォーム PDF 開発ツール
Aspose Aspose
.NET/Java で Word、Excel、PowerPoint、PDF などの Office ファイルを操作できる API ライブラリ。
Visual Studio Microsoft Visual Studio
最新の統合開発環境!アプリケーションの迅速かつ高品質な構築を支援する開発環境を提供。