Xamarin.Forms 入門

 

クロスプラットフォーム UI 開発の入門ガイド

Xamarin.Forms は、クロスプラットフォームのネイティブ UI (ユーザー インターフェース) の開発を支援する抽象化レイヤーを提供し、開発者は Xamarin.Forms を使用して、Android、iOS、Windows Phone 間で共有可能な UI を簡単に作成できます。ターゲットのプラットフォームのネイティブ コントロールを使用して UI をレンダリングし、Xamarin.Forms を使用して開発したアプリケーションは各プラットフォームの最適なルック アンド フィールを提供できます。本ガイドでは、Xamarin.Forms の概要の紹介と Xamarin.Forms を使用したアプリケーションの作成方法を紹介します。

概要

Xamarin.Forms は、開発者が素早く簡単にクロスプラットフォームの UI を作成できるフレームワークです。Xamarin.Forms は UI 用の 抽象化レイヤーを提供し、iOS、Android、Windows Phone でネイティブ コントロールを使用してレンダリングします。つまり、対象のアプリケーションでは、UI コードの大部分を共有でき、かつターゲット プラットフォームのネイティブのルック アンド フィールを提供できます。

Xamarin.Forms は C# で記述されており、迅速にアプリケーションのプロトタイプ化ができ、高度なアプリケーションを時間とともに進化できます。Xamarin.Forms で開発したアプリケーションはネイティブ アプリケーションなので、ブラウザ サンドボックスなどの他のツールキットの制限、使用できる API の制限などはなく、高いパフォーマンスを提供できます。Xamarin.Forms を使用して開発したアプリケーションは、各プラットフォームが提供するすべての API や機能を使用できます (iOS の CoreMotion、PassKit、StoreKit、Android の NFC、Google Play Services、Windows Phone の Tiles など、またこれらに限らず)。つまり、Xamarin.Forms で作成した UI 部分とネイティブ UI ツールキットを使用して作成した UI 部分の両方を持つアプリケーションを開発することもできます。

Xamarin.Forms で開発したアプリケーションは、トラディショナルなクロスプラットフォーム アプリケーションと同じ方法で構成されています。最も一般的なアプローチは、Portable Libraries、または Shared Projects を使用して共有コードを作成し、共有コードを使用するプラットフォーム独自のアプリケーションを作成します。

Xamarin.Forms では、UI の作成方法は 2種類あります。一つ目の方法は、Xamarin.Forms が提供する豊富な API を使用してソースコードを記述して、UI ビュー全体を作成します。二つ目の方法は、XAML (Extensible Application Markup Language、マイクロソフト社が提供する宣言型マークアップ言語で UI を記述するのに使用します) を使用します。UI 自体を XAML のシンタックスを使用する XML ファイルで定義し、一方で Run Time の動作を別の Code-Behind ファイルに定義します。XAML に関しては、マイクロソフト社の関連するドキュメント What is XAMLXAML Overview を参照してください。

本ガイドでは、Xamarin.Forms のフレームワークの基礎を紹介します。以下のトピックをカバーします:

  • Xamarin.Forms のインストール
  • Visual Studio または Xamarin Studio で Xamarin.Forms のソリューションを設定
  • Xamarin.Forms のページとコントロールの使用方法
  • ページ間のネビゲーション方法
  • データ バインディングの設定方法

要件

Xamarin.Forms は、以下のモバイル オペレーション システムのアプリケーションを作成することができます:

  • Android 4.0 以降のバージョン
  • iOS 6.1 以降のバージョン
  • Windows Phone 8 (Visual Studio 必須)

Xamarin.Forms では、一部のコントロール (DatePicker など) とアニメーション用に Windows Phone Toolkit を利用します。この Toolkit は自動的に NuGet の参照として追加されます。

Portable Class LibrariesShared Projects に関しては、既に習得済みとして本ガイドを進めます。

 

Mac のシステム要件

OS X で Xamarin.Forms のアプリケーションを開発するには Xamarin Studio 5 が必要です。また iOS アプリケーションの開発には Xcode 5 も必要です。(OS X 10.8 Mountain Lion 以降)

Windows Phone アプリは、OS X では、開発できません。OS X で作成した場合、新しいソリューション テンプレートには、Windows Phone のプロジェクトは含まれません。

 

Windows のシステム要件

iOS と Android の Xamarin.Forms アプリケーションは、Xamarin の開発に必要な環境、Visual Studio 2012 以降のバージョンがインストールされた Windows 7 以降の OS であれば、どの Windows でもビルドすることができます。iOS の開発には Mac をネットワーク上に配置する必要があります。

Windows Phone Silverlight 8 に対応する Xamarin.Forms アプリケーションでは、以下が必要です:

  • Windows 8
  • Windows Phone SDK がインストールされた Visual Studio 2013 以降。これらのシステム要件を満たしていない場合、Windows Phone のプロジェクトでは "Project type not supported" エラーが発生します。

PCL ソリューションのテンプレートでは、.NET 4.5 をターゲットとした Profile 78 が必要です。この .NET 4.5 バージョンは、Visual Studio 2012 でインストールすることができます (および Visual Studio 2013 にも含まれます)。Windows Phone SDK をインストールしない場合、"Project type not supported" エラーが発生します。

Shared Project ソリューションのテンプレートでは、Visual Studio 2013 Update 2 が必要です。

Xamarin Forms 入門ガイド

前述のように、Xamarin.Forms を .NET の PCL (Portable Class Library) として実装し、さまざまなプラットフォーム間で Xamarin.Forms の API を非常に簡単に共有します。入門ガイドの最初のステップは、アプリケーションを構成するさまざまなプロジェクト用にソリューションを作成します。

Xamarin Studio または Visual Studio で Xamarin.Forms のソリューションを作成可能で、基本的には以下のプロジェクトを含みます:

  • Portable Library - このプロジェクトは、クロスプラットフォーム アプリケーションのライブラリで、すべての共有コードと UI を持ちます。
  • Xamarin.Android Application - このプロジェクトは、Android 固有のコードを持ち、Android アプリケーションのエントリーポイントです。
  • Xamarin.iOS Application - このプロジェクトは、iOS 固有のコードを持ち、iOS アプリケーションのエントリーポイントです。
  • Windows Phone Application - このプロジェクトは、Windows Phone 固有のコードを持ち、Windows Phone アプリケーションのエントリーポイントです。

Xamarin 3.0 では、Xamarin.Forms のアプリケーションに必要なすべてのプロジェクトを含む完全なソリューションを作成するテンプレートを提供します。

本ガイドで利用できる Xamarin.Forms のサンプルは、下の一覧からダウンロードできます。

 

Xamarin Studio

Xamarin Studio では、ファイル > 新規 > ソリューションを選択します。新しいソリューションのダイアログが表示され、Cross Platform > App をクリックし、ダイアログ中央付近にある Blank Xamarin.Forms App プロジェクトを選択します。以下のスクリーンショットを参照してください:

Xamarin.Forms app の設定を次の画面で行います。アプリケーションに名前を付け、ターゲットにするプラットフォームを選択し、使用する Portable Class Library または Shared Library を選択します。デフォルトでは、PCL が選択されています。

プロジェクト名を入力し、OK ボタンをクリックします。テンプレートでは 3つのプロジェクトを持つ新しいソリューションを生成します。以下のスクリーンショットを参照してください:

Xamarin Studio でソリューションを生成した場合、Windows Phone プロジェクトは含まれません。Visual Studio を使用して Xamarin.Forms ソリューションを作成した場合は、iOS と Android と同様に Windows Phone もサポートします。Xamarin Studio は、Windows Phone アプリケーションの作成をサポートしてませんが、既に作成されたソリューション (例えば、Visual Studio で作成されたソリューション) を読み込むことは可能です。つまり Xamarin Studio で Windows Phone のコードを確認することは可能ですが、ビルドや実行することはできません。

 

Visual Studio

Visual Studio では、ファイル > 新規作成 > プロジェクトを選択します。新しいプロジェクトのダイアログが表示され、テンプレート > Visual C# > Mobile Apps をクリックし、ダイアログ中央付近にある Blank App (Xamarin.Forms Portable) プロジェクトを選択します。以下のスクリーンショットを参照してください:

プロジェクト名を入力し、OK ボタンをクリックします。テンプレートでは、4つのプロジェクトを持つソリューションを作成します。以下のスクリーンショットを参照してください:

 

Xamarin.Forms のアプリケーションのテスト

デフォルトのテンプレートでは可能な限り一番シンプルな Xamarin.Forms のソリューションを作成します。アプリケーションを実行すると、以下のスクリーンショットのように同じような画面が表示されます:

上記のスクリーンショット内の各画面は、Xamarin.Forms の Page です。Xamarin.Forms.Page では、Android の Activity、iOS の View Controller、Windows Phone の Page を表します。上記の HelloXamarinFormsWorld のスクリーンショットでは、Xamarin.Forms.ContentPage オブジェクトをインスタンス化し、ラベルを表示するのに使用しています。

スタートアップ コードを最大限再利用するために、Xamarin.Forms アプリケーションでは、App と名前付けしたシングル クラスを持ち、最初のページのインスタンス化に対応し、ページを表示します。以下、App クラスのサンプルのコードです:

public class App : Application
{
  public App ()
  {
    MainPage = new ContentPage {
      Content =  new Label
      {
        Text = "Hello, Forms !",
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.CenterAndExpand,
      }
    };
  }
}

このコードは、新しい ContentPage オブジェクトをインスタンス化し、ページ上の垂直方向と水平方向の中央にシングル ラベルを表示します。

 

各プラットフォームに最初の Xamarin.Forms のページを表示。

アプリケーション内の Page を使用して、各プラットフォームのアプリケーションは、Xamarin.Forms のフレームワークを初期化する必要があり、その後、起動する際に、ContentPage のインスタンスを提供します。この初期化ステップは、プラットフォームごとに異なり、以下のセクションで紹介します。

Android

Android で最初の Xamarin.Forms のページを起動するには、トラディショナルな Android アプリケーションのように MainLauncher の属性を持つ Activity を作成し (Xamarin.Forms.Platform.Android.FormsApplicationActivity から継承する Activity を除く)、Xamarin.Forms のフレームワークを初期化し、Xamarin.Forms のアプリケーションをロードします。以下のサンプル コードは、アクション時のパターンとなります:

namespace HelloXamarinFormsWorld.Android
{
    [Activity(Label = "HelloXamarinFormsWorld",
        MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : FormsApplicationActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication (new App ());
        }
    }
}

上記のコードは、Xamarin.Android のアプリケーションを作成し、Xamarin.Forms のフレームワークを初期化し、共有 UI コードを実行します。

iOS

Xamarin.iOS のアプリケーションの場合、AppDelegate クラスは Xamarin.Forms.Platform.iOS.FormsApplicationDelegate から継承する必要があり、Xamarin.Forms のフレームワークを初期化し、Xamarin.Forms のアプリケーションを起動します。以下のコードのように、FinishedLaunching メソッド内部で実行します:

[Register("AppDelegate")]
public partial class AppDelegate : FormsApplicationDelegate
{
    UIWindow window;
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        Forms.Init();
        window = new UIWindow(UIScreen.MainScreen.Bounds);
        LoadApplication (new App ());
        return base.FinishedLaunching (app, options);
    }
}

Android アプリケーションと同じように、FinishedLaunching イベントの最初のステップは、Xamarin.Forms.Forms.Init() への呼び出しで Xamarin.Forms フレームワークを初期化します。本ステップには、Xamarin.Forms の iOS 独自の実装があるので、アプリケーションでグローバルにロードします。次のステップでは、LoadApplication メソッドから root view controller をセットして、Xamarin.Forms のアプリケーションをスタートします。

Windows Phone

Windows Phone プロジェクトのスタートアップ ページの場合、Xamarin.Forms フレームワークを初期化し、LoadApplication を呼び出すことでスタートアップ ページを設定します。下記のコードは、実行方法のサンプルです:

public partial class MainPage : FormsApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
        SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;
        Forms.Init();
        LoadApplication(new YOUR_APP_NAMESPACE.App());
    }
}

Xamarin.Forms の概要を説明しましたが、さらに Xamarin.Forms のアプリケーションの機能の詳細を紹介します。

 

表示とレイアウト

Xamarin.Forms では、シングル API を提供して、コントロールとレイアウトを持つ UI を作ります。実行時に、Xamarin.Forms のコントロールを対応するネイティブ コントロールにマッピングし、レンダリングします。4つの主要なクラスを使用して Xamarin.Forms のアプリを構成します:

  • View - これは一般的には他のプラットフォームではコントロールやウィジットとして参照されます。ラベル、ボタン、テキスト フィールドなどの UI エレメントに該当します。
  • Page - Xamarin.Forms では、アプリケーションでシングル スクリーンを表示します。これらは、Android の Activity、Windows Phone の Page、iOS の View Controller と同様です。
  • Layout - これは特殊な View のサブタイプです。つまり、他の Layout や View ではコンテナとして機能します。Layout のサブタイプには、基本的に特定の方法で子ビューを編成する独自のロジックが含まれます。
  • Cell - このクラスは特殊なエレメントで、リストやテーブルのアイテムに使用します。これは、リストの各項目を描画する方法を説明します。

以下の表は、一般的なコントロールの一部のリストです:

Xamarin.Forms のコントロール説明
Label読み取り専用のテキストを表示するコントロールです。
Entryシンプルなシングル ラインのテキスト入力コントロールです。
Buttonコマンドの開始に使用します。
Imageビットマップを表示するのに使用するコントロールです。
ListViewアイテムのリストをスクロールするのに使用します。リスト内のアイテムは、Cell と呼びます。

コントロール自身をレイアウト内部でホストします。Xamarin.Forms は、二つの異なるカテゴリのレイアウトを持ち、さまざまな方法でコントロールをアレンジします:

  • Managed Layouts - 画面上で子コントロールの位置やサイズを制御するレイアウトで、CSS box model に準拠します。アプリケーションでは、子コントロールのサイズや位置を直接設定しないでください。Managed Xamarin.Forms のレイアウトの一般的な例の一つとしては、StackLayout があります。
  • Unmanaged Layouts - Managed レイアウトと対照的に、Unmanaged レイアウトは、画面上で子コントロールのアレンジまたはポジショニングをしません。基本的に、ユーザーは、レイアウトに子コントロールを追加する際には、子コントロールのサイズとロケーションを指定します。AbsoluteLayout は、Unmanaged レイアウト コントロールの例の一つです。

下記で StackLayoutAbsoluteLayout について詳しく紹介します。

StackLayout

StackLayout は、非常に一般的な Managed レイアウトです。StackLayout は、画面のサイズを気にすることなく画面上のコントロールを自動的にアレンジすることで、クロスプラットフォーム アプリケーションの開発を大幅に簡素化します。それぞれの子エレメントを追加した順番に、水平方向または垂直方向に、順番に配置します。StackLayout が使用するスペースは HorizontalOptionsLayoutOptions のプロパティの設定方法で決まります。ただし、デフォルトでは、StackLayout は、画面全体を使用します。

以下のコードは、StackLayout を使用して、画面上に 3つの StackLayout コントロールをアレンジする例です:

public class StackLayoutExample: ContentPage
{
    public StackLayoutExample()
    {
        Padding = new Thickness(20);
        var red = new Label
        {
            Text = "Stop",
            BackgroundColor = Color.Red,
            Font = Font.SystemFontOfSize (20)
        };
        var yellow = new Label
        {
            Text = "Slow down",
            BackgroundColor = Color.Yellow,
            Font = Font.SystemFontOfSize (20)
        };
        var green = new Label
        {
            Text = "Go",
            BackgroundColor = Color.Green,
            Font = Font.SystemFontOfSize (20)
        };
        Content = new StackLayout
        {
            Spacing = 10,
            Children = { red, yellow, green }
        };
    }
}

以下のコードは、同じレイアウトで XAML を使用した場合です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                       x:Class="HelloXamarinFormsWorldXaml.StackLayoutExample1"
             Padding="20">
  <StackLayout Spacing="10">
    <Label Text="Stop"
           BackgroundColor="Red"
           Font="20" />
    <Label Text="Slow down"
           BackgroundColor="Yellow"
           Font="20" />
    <Label Text="Go"
           BackgroundColor="Green"
           Font="20" />
  </StackLayout>
</ContentPage>

デフォルトでは、StackLayout は、以下のスクリーンショットのように、垂直方向に配置されます:

以下のコードを使用して、方向と垂直のオプションを変更できます:

public class StackLayoutExample: ContentPage
{
    public StackLayoutExample()
    {
        // Code that creates labels removed for clarity
        Content = new StackLayout
        {
            Spacing = 10,
            VerticalOptions = LayoutOptions.End,
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.Start,
            Children = { red, yellow, green }
        };
    }
}

以下のコードは、同じレイアウトで XAML を使用した場合です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="HelloXamarinFormsWorldXaml.StackLayoutExample2"
             Padding="20">
  <StackLayout Spacing="10"
               VerticalOptions="End"
               Orientation="Horizontal"
               HorizontalOptions="Start">
    <Label Text="Stop"
           BackgroundColor="Red"
           Font="20" />
    <Label Text="Slow down"
           BackgroundColor="Yellow"
           Font="20" />
    <Label Text="Go"
           BackgroundColor="Green"
           Font="20" />
  </StackLayout>
</ContentPage>

以下のイメージは、上記のコードを変更後のスクリーンのイメージです:

StackLayout の子コントロールのサイズを明示的に指定することはできませんが、HeightRequestWidthRequest のプロパティを使用してレイアウト エンジンにヒントを提供できます。以下のコードは、各ラベルの幅の要求方法です:

var red = new Label
{
    Text = "Stop",
    BackgroundColor = Color.Red,
    Font = Font.SystemFontOfSize (20),
    WidthRequest = 100
};
var yellow = new Label
{
    Text = "Slow down",
    BackgroundColor = Color.Yellow,
    Font = Font.SystemFontOfSize (20),
    WidthRequest = 100
};
var green = new Label
{
    Text = "Go",
    BackgroundColor = Color.Green,
    Font = Font.SystemFontOfSize (20),
    WidthRequest = 200
};
Content = new StackLayout
{
    Spacing = 10,
    VerticalOptions = LayoutOptions.End,
    Orientation = StackOrientation.Horizontal,
    HorizontalOptions = LayoutOptions.Start,
    Children = { red, yellow, green }
};

以下のコードは、上記のようなレイアウトで XAML を使用した一例です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="HelloXamarinFormsWorldXaml.StackLayoutExample3"
             Padding="20">
  <StackLayout Spacing="10"
               VerticalOptions="End"
               Orientation="Horizontal"
               HorizontalOptions="Start">
    <Label Text="Stop"
           BackgroundColor="Red"
           Font="20"
           WidthRequest="100" />
    <Label Text="Slow down"
           BackgroundColor="Yellow"
           Font="20"
           WidthRequest="100" />
    <Label Text="Go"
           BackgroundColor="Green"
           Font="20"
           WidthRequest="200" />
  </StackLayout>
</ContentPage>

以下のスクリーンショットは、上記の提案を実行した StackLayout のイメージです:

Absolute Layout

StackLayout とは対照に、AbsoluteLayout は、Unmanaged レイアウトです。各コントロールをレイアウト内で明示的に位置を指定する必要があります。概念的には (制限なしで) iOS のコントロールの配置方法または、古い Windows Forms のスタイルによく似ています。これにより、コントロールの正確な配置を行うことができますが、この方法は、さまざまなな画面サイズで余計なテストを行う必要があります。

以下のコードは、シンプルな AbsoluteLayout の一例です:

public class MyAbsoluteLayoutPage : ContentPage
{
    public MyAbsoluteLayoutPage()
    {
        var red = new Label
        {
            Text = "Stop",
            BackgroundColor = Color.Red,
            Font = Font.SystemFontOfSize (20),
            WidthRequest = 200,
            HeightRequest = 30
        };
        var yellow = new Label
        {
            Text = "Slow down",
            BackgroundColor = Color.Yellow,
            Font = Font.SystemFontOfSize (20),
            WidthRequest = 160,
            HeightRequest = 160
        };
        var green = new Label
        {
            Text = "Go",
            BackgroundColor = Color.Green,
            Font = Font.SystemFontOfSize (20),
            WidthRequest = 50,
            HeightRequest = 50
        };
        var absLayout = new AbsoluteLayout();
        absLayout.Children.Add(red, new Point(20,20));
        absLayout.Children.Add(yellow, new Point(40,60));
        absLayout.Children.Add(green, new Point(80,180));
        Content = absLayout;
    }
}

以下の XML コードは、以前の C# コードの XAML の実装です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                       x:Class="HelloXamarinFormsWorldXaml.AbsoluteLayoutExample"
             Padding="20">
  <AbsoluteLayout>
    <Label Text="Stop"
           BackgroundColor="Red"
           Font="20"
           AbsoluteLayout.LayoutBounds="20,20,200,30" />
    <Label Text="Slow down"
           BackgroundColor="Yellow"
           Font="20"
           AbsoluteLayout.LayoutBounds="40,60,160,160" />
    <Label Text="Go"
           BackgroundColor="Green"
           Font="20"
           AbsoluteLayout.LayoutBounds="80,180,50,50" />
  </AbsoluteLayout>
</ContentPage>

レンダリングした場合、本ページは以下のスクリーンショットのようになります:

コントロールを Children コレクションへ追加した順番がスクリーンのエレメントの Z-order に影響するので注意してください – 最初のコントロールは Z-order の‘bottom’で表示され、次のコントロールをより高く追加し、オーバーラップできます (この例で緑のラベルが行っているように)。コントロールを絶対位置で配置する場合、他のコントロールを完全に隠したりしないように、誤ってスクリーンの端からはみ出さないように注意が必要です。

Xamarin.Forms の List

ListViews は、モバイル アプリケーションでは非常に一般的なコントロールなので、少し詳細に紹介します。ListViews は、画面のアイテムのコレクションの表示を処理し、ListViews の各アイテムを単一のセル内に格納されます。デフォルトでは、ListViews はビルトインの TextCell テンプレートを使用し、単一の行のテキストをレンダリングします。以下のコードは、ListViews を使用したシンプルな例です:

var listView = new ListView
{
    RowHeight = 40
};
listView.ItemsSource = new string []
    {
        "Buy pears",
        "Buy oranges",
        "Buy mangos",
        "Buy apples",
        "Buy bananas"
    };
Content = new StackLayout
{
    VerticalOptions = LayoutOptions.FillAndExpand,
    Children = { listView }
};

上記のコードを実行した場合、下のスクリーンショットにように表示します:

 

Custom Class へバインディング

カスタム オブジェクトをデフォルトの TextCell テンプレートを使用して ListViews で表示します。以下、TodoItem のクラス定義を使用します:

public class TodoItem {
    public string Name { get; set; }
    public bool Done { get; set; }
}

ListViews に以下のように値を設定します:

listView.ItemsSource = new TodoItem [] {
    new TodoItem {Name = "Buy pears"},
    new TodoItem {Name = "Buy oranges", Done=true},
    new TodoItem {Name = "Buy mangos"},
    new TodoItem {Name = "Buy apples", Done=true},
    new TodoItem {Name = "Buy bananas", Done=true}
};

リスト内にどのプロパティを表示するかコントロールするには、プロパティにパスを指定するバインディングを作成します。以下のケースでは、Name プロパティです:

listView.ItemTemplate = new DataTemplate(typeof(TextCell));
listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Name");

このコードは、上記の例と同じようにレンダリングします。

 

ListView のアイテムの選択

ユーザーが ListViews のセルをタッチした場合に、ItemSelected イベントを実装して、以下のように簡単なアラートを表示して対応します:

listView.ItemSelected += async (sender, e) => {
    await DisplayAlert("Tapped!", e.SelectedItem + " was tapped.", "OK");
};

NavigationPage 内に含まれる場合、Navigation.PushAsync メソッドを使って、ビルトインの "戻る" で新しいページを開くことができます。ItemSelected イベントは、e.SelectedItem を使用してセルに関連付けたオブジェクトへアクセスし、新しいページにバインドし、PushAsync を使用して新しいページを表示します:

listView.ItemSelected += async (sender, e) => {
    var todoItem = (TodoItem)e.SelectedItem;
    var todoPage = new TodoItemPage(todoItem); // so the new page shows correct data
    await Navigation.PushAsync(todoPage);
};

各プラットフォームでのビルトインの "戻る" の実装方法は違います。下記の Navigation セクションにて詳細を紹介します。

 

Cell の表示をカスタマイズ

ViewCell をサブクラス化して、このクラスのタイプを ListView の ItemTemplate のプロパティに設定することでセルをカスタマイズできます。

以下、ListView のセルのスクリーンショットです:

このセルは、1つの Image コントロールと 2つの Label ビューで構成されています。このカスタム レイアウトを作成するには、以下のサンプルのクラスのように、ViewCell をサブクラス化します:

class EmployeeCell : ViewCell
{
    public EmployeeCell()
    {
        var image = new Image
                    {
                        HorizontalOptions = LayoutOptions.Start
                    };
        image.SetBinding(Image.SourceProperty, new Binding("ImageUri"));
        image.WidthRequest = image.HeightRequest = 40;
        var nameLayout = CreateNameLayout();
        var viewLayout = new StackLayout()
                         {
                             Orientation = StackOrientation.Horizontal,
                             Children = { image, nameLayout }
                         };
        View = viewLayout;
    }
    static StackLayout CreateNameLayout()
    {
        var nameLabel = new Label
                        {
                            HorizontalOptions= LayoutOptions.FillAndExpand
                        };
        nameLabel.SetBinding(Label.TextProperty, "DisplayName");
        var twitterLabel = new Label
                           {
                               HorizontalOptions = LayoutOptions.FillAndExpand,
                               Font = Fonts.Twitter
                           };
        twitterLabel.SetBinding(Label.TextProperty, "Twitter");
        var nameLayout = new StackLayout()
                         {
                             HorizontalOptions = LayoutOptions.StartAndExpand,
                             Orientation = StackOrientation.Vertical,
                             Children = { nameLabel, twitterLabel }
                         };
        return nameLayout;
    }
}

このコードには以下の内容が含まれます:

  • Image を追加し、Employee オブジェクトの ImageUri プロパティにバインドします。データ バインディングについては、後ほど紹介します。
  • 垂直方向に StackLayout を作成して二つの Label を固定します。LabelsDisplayName プロパティと Employee オブジェクトの Twitter プロパティにバインドします。
  • 上記の 2つのステップから、ImageStackLayout をホストする別の StackLayout を作成します。子を水平方向に指定してアレンジします。

カスタム セルを作成したら、以下のように DataTemplate でラッピングすることで ListView コントロールと一緒に使用できます:

List<Employee> myListOfEmployeeObjects = GetAListOfAllEmployees();
var listView = new ListView
{
    RowHeight = 40
};
listView.ItemsSource = myListOfEmployeeObjects;
listView.ItemTemplate = new DataTemplate(typeof(EmployeeCell));

上記のコードは、List<employee> オブジェクトを ListView に提供します。各セルを EmployeeCell クラスを使用してレンダリングします。ListView は、Employee オブジェクトをその BindingContext として EmployeeCell に渡します。

 

XAML を使用して List を作成、カスタマイズ

以下のコードは、上記のセクションと同様のリストを XAML を使用した場合です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:XamarinFormsXamlSample;assembly=XamarinFormsXamlSample"
             xmlns:constants="clr-namespace:XamarinFormsSample;assembly=XamarinFormsXamlSample"
             x:Class="XamarinFormsXamlSample.Views.EmployeeListPage"
             Title="Employee List">
  <ListView x:Name="listView"
            IsVisible="false"
            ItemsSource="{x:Static local:App.Employees}"
            ItemSelected="EmployeeListOnItemSelected">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <ViewCell.View>
            <StackLayout Orientation="Horizontal">
              <Image Source="{Binding ImageUri}"
                     WidthRequest="40"
                     HeightRequest="40" />
              <StackLayout Orientation="Vertical"
                           HorizontalOptions="StartAndExpand">
                <Label Text="{Binding DisplayName}"
                       HorizontalOptions="FillAndExpand" />
                <Label Text="{Binding Twitter}"
                       Font="{x:Static constants:Fonts.Twitter}"/>
              </StackLayout>
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

上記の XAML のコードは、ListView を含む ContentPage を定義します。ListView のデータソースを ItemsSource 属性を使用して設定します。ItemsSource の各行のレイアウトを ListView.ItemTemplate エレメント内で定義します。

データ バインディング

データ バインディングを使用して、Xamarin.Forms のアプリケーションでデータを表示したりデータと対話する方法を簡素化します。データ バインディングは UI と下位のアプリケーション間の接続を確立します。ユーザーがテキスト ボックスの値を変更する際、データ バインディングによって、下位のオブジェクトに関連付けしたプロパティを自動的に更新します。BindableObject クラスには、データ バインディングをサポートするインフラが多く含まれています。

データ バインディングでは、2つのオブジェクト間の関係を定義します。ソース オブジェクトは、データを提供します。ターゲット オブジェクトは、ソース オブジェクトからデータを消費 (また、表示も) する別のオブジェクトです。例えば、Label は、Employee クラスの Name を表示する可能性があります。この場合、Employee オブジェクトはソースとなり、一方で Label はターゲットととなります。

Xamarin.Forms オブジェクト (Page や Control など) のデータ バインディングの設定には、以下の 2つのステップがあります:

  • BindingContext プロパティをバインドするオブジェクトに設定します。バインド オブジェクトは INotifyPropertyChanged インターフェースを実装する任意の .NET オブジェクトです (後で説明します) 。
  • バインディングする各プロパティまたはメソッドに対して 1回 Xamarin.Forms のオブジェクトで SetBinding メソッドを呼び出します。

SetBinding メソッドには、2つのパラメーターがあります。一つ目のパラメーターは、バインディングのタイプに関する情報を指定します。2つ目のパラメーターは、何をどのようにバインディングするかに関する情報を提供するために使用されます。2つ目のパラメーターは、ほとんどの場合、BindingContext のプロパティの名前を保持する文字列です。BindingContext に直接バインディングしたい場合は、下記のシンタックスを使用することができます:

someLabel.SetBinding(Label.TextProperty, new Binding("."));

ドット シンタックスは、BindingContext のプロパティの代わりにデータソースとして、BindingContext を使うように Xamarin.Forms を指定します。BindingContext が文字列や整数型などよりシンプルなタイプにすると、使いやすいです。

以下のスクリーンショットを参考に、Xamarin.Forms のページのデータ バインディングの設定方法に説明します:

このページには、以下のコントロールが含まれます:

  • Xamarin.Forms.Image
  • Xamarin.Forms.Label
  • Xamarin.Forms.Entry
  • Xamarin.Forms.Button

この画面を構成するページでは、コンストラクター経由で Employee オブジェクトのインスタンスを渡します。以下のコードは、コンストラクターの例です:

public EmployeeDetailPage(Employee employeeToDisplay)
{
    this.BindingContext = employeeToDisplay;
    var firstName = new Entry()
                {
                    HorizontalOptions = LayoutOptions.FillAndExpand
                };
    firstName.SetBinding(Entry.TextProperty, "FirstName");
    // Rest of the code omitted…
}

コードの 1行目は、BindingContext を .NET オブジェクトに設定します。どのオブジェクトをバインディングするか下位のデータ バインディングの API を指定します。次の行のコードは、 Xamarin.Forms.Entry コントロールをインスタンス化します。最後の行では、Xamarin.Forms.EntryemployeeToDisplay の間のバインディングを定義します。Entry.Text プロパティをオブジェクトの FirstName プロパティにバインディングし、BindingContext へ設定します。Entry コントロールで行った変更を自動的に employeeToDisplay オブジェクトへ展開します。同様に、emplayeeToDisplay.FirstName を変更した場合、Xamarin.Forms も Entry コントロールの内容を更新します。これを two-way バインディングと呼びます。

正常に two-way バインディングを動作させるには、モデル クラスでは、次のセクションで紹介する INotifyPropertyChanged を実装する必要があります。

 

INotifyPropertyChanged

InotifyPropertyChanged インターフェースを使用して、値を変更したオブジェクトのクライアントに通知します。インターフェースは、非常にシンプルです:

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

これらのプロパティの一つを新しい値で更新すると、INotifyPropertyChanged を実装するオブジェクトは、PropertyChanged イベントを発生させる必要があります。そのクラスの例は、以下のクラスから確認できます:

public class MyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (value.Equals(_firstName, StringComparison.Ordinal))
            {
                // Nothing to do - the value hasn't changed;
                return;
            }
            _firstName = value;
            OnPropertyChanged();
        }
    }
    void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MyObject のインスタンスが FirstName を変更すると、OnPorpertyChanged メソッドを呼び出し、PropertyChanged イベントが発生します。

propertyName パラメーターを CallerMemberName 属性で使用しているので注意してください。OnPropertyChanged メソッドを null 値で呼び出す場合、CallerMemberName 属性は、OnPropertyChanged を呼び出したメソッドの名前を渡します。

ナビゲーション

ページの作成方法とコントロールの配置方法を紹介しましたので、他のページへのナビゲーション方法を紹介します。ナビゲーションは、ページ オブジェクトの last-in / first-out スタックと考えることができます。他のページへ移動するには、アプリケーションはこのスタックの新しいページをプッシュします。前のページへ戻るには、アプリケーションはスタックから現在のページをポップします。Xamarin.Forms のナビゲーションは、以下のメソッドを提供する INavigation インターフェースによって処理されます。

public interface INavigation
{
    Task PushAsync(Page page);
    Task<Page> PopAsync();
    Task PopToRootAsync();
    Task PushModalAsync(Page page);
    Task<Page> PopModalAsync();
}

これらのメソッドは、Task を返して、呼び出したコードで Push または Pop が成功したか確認します。

Xamarin.Forms には、NavigationPage クラスがあり、このインターフェースを実装したり、ページのスタックを管理します。NavigationPage クラスは、ナビゲーション バーを画面の上位に追加し、タイトルを表示し、プラットフォームごとに最適な戻るボタンを提供し、前のページへ戻ります。以下のコードでは、アプリケーションの最初のページで NavigationPage をラップする方法を紹介します:

public static Page GetMainPage()
{
    var mainNav = new NavigationPage(new EmployeeListPage());
    return mainNav;
}

以下のコードのように、現在のページの LoginPage を表示するには、INavigation.PushAsync を呼び出す必要があります:

await Navigation.PushAsync(new LoginPage());

これにより、新しい LoginPage オブジェクトをナビゲーション スタックでプッシュします。オリジナル ページに戻るには、LoginPage を呼び出す必要があります:

await Navigation.PopAsync();

モデル ナビゲーションも同様です。以下のコードは、新しいページのモーダルを表示します:

await Navigation.PushModalAsync(new LoginPage());

呼び出し元のページに戻るには、LoginPage を呼び出す必要があります:

await Navigation.PopModalAsync();

まとめ

本ガイドでは、Xamarin.Forms の概要を紹介し、Xamarin.Forms を使用してクロスプラットフォームのアプリケーションを作成する方法を紹介しました。Xamarin.Forms のインストール方法とソリューションの設定方法を紹介しました。プラットフォームのネイティブなルック アンド フィールを維持したまま共通の UI を持つ Xamarin.Forms のアプリケーションの作成方法を紹介しました。また、UI 間と下位のデータ間のデータ バインディングの設定方法と Page 間のナビゲーション方法を紹介しました。

 

 


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
最新の統合開発環境!アプリケーションの迅速かつ高品質な構築を支援する開発環境を提供。