Xamarin.Forms クイック スタート Deep Dive

Xamarin.Forms クイック スタートでは、Notes アプリケーションをビルドしました。 この記事では、Xamarin.Forms シェル アプリケーションのしくみの基礎を理解するために構築された内容を確認します。

Visual Studio の概要

Visual Studio は、コードをソリューションプロジェクトに分けて整理しています。 ソリューションとは、1 つまたは複数のプロジェクトを保持できるコンテナーです。 プロジェクトは、アプリケーション、サポートするライブラリ、テスト アプリケーションなどの場合があります。 Notes アプリケーションは、次のスクリーンショットに示されているように、3 つのプロジェクトを含む 1 つのソリューションで構成されています。

Visual Studio Solution Explorer

プロジェクトの内容:

  • Notes - このプロジェクトは、すべての共有コードと共有 UI を保持する .NET Standard ライブラリ プロジェクトです。
  • Notes.Android: このプロジェクトは、Android 固有のコードを保持しており、Android アプリケーションのエントリ ポイントです。
  • Notes.iOS: このプロジェクトは、iOS 固有のコードを保持しており、iOS アプリケーションのエントリ ポイントです。

Xamarin.Forms アプリケーションの構造

次のスクリーンショットは、Visual Studio の Notes .NET Standard プロジェクトの内容です。

Phoneword .NET Standard Project Contents

このプロジェクトには、NuGet ノードと SDK ノードを含む Dependencies ノードがあります。

  • NuGet – Xamarin.Forms、Xamarin.Essentials、プロジェクトに追加されている Newtonsoft.Json、sqlite-net-pcl の各 NuGet パッケージ。
  • SDK – .NET Standard を定義する NuGet パッケージの完全なセットを参照する NETStandard.Library メタパッケージ。

Visual Studio for Mac の概要

Visual Studio for Mac は、コードをソリューションプロジェクトに分けて整理するという Visual Studio の方法に従っています。 ソリューションとは、1 つまたは複数のプロジェクトを保持できるコンテナーです。 プロジェクトは、アプリケーション、サポートするライブラリ、テスト アプリケーションなどの場合があります。 Notes アプリケーションは、次のスクリーンショットに示されているように、3 つのプロジェクトを含む 1 つのソリューションで構成されています。

Visual Studio for Mac Solution Pane

プロジェクトの内容:

  • Notes - このプロジェクトは、すべての共有コードと共有 UI を保持する .NET Standard ライブラリ プロジェクトです。
  • Notes.Android: このプロジェクトは、Android 固有のコードを保持した、Android アプリケーションのエントリ ポイントです。
  • Notes.iOS: このプロジェクトは、iOS 固有のコードを保持しており、iOS アプリケーションのエントリ ポイントです。

Xamarin.Forms アプリケーションの構造

次のスクリーンショットは、Visual Studio for Mac の Notes .NET Standard プロジェクトの内容を示しています。

Phoneword .NET Standard Library Project Contents

このプロジェクトには、NuGet ノードと SDK ノードを含む Dependencies ノードがあります。

  • NuGet – Xamarin.Forms、Xamarin.Essentials、プロジェクトに追加されている Newtonsoft.Json、sqlite-net-pcl の各 NuGet パッケージ。
  • SDK – .NET Standard を定義する NuGet パッケージの完全なセットを参照する NETStandard.Library メタパッケージ。

このプロジェクトには、複数のファイルも含まれています。

  • Data\NoteDatabase.cs – このクラスには、データベースを作成し、それに対してデータの読み込み、データの書き込み、データの削除を行うためのコードが含まれます。
  • Models\Note.cs – このクラスにより、Note モデルが定義されます。このインスタンスにアプリケーション内の各メモに関するデータが格納されます。
  • Views\AboutPage.xamlAboutPage クラスの XAML マークアップ。About ページの UI が定義されています。
  • Views\AboutPage.xaml.csAboutPage クラスのコードビハインド。ユーザーがページを操作するときに実行されるビジネス ロジックが含まれています。
  • Views\NotesPage.xamlNotesPage クラスの XAML マークアップ。アプリケーションの起動時に表示されるページの UI が定義されています。
  • Views\NotesPage.xaml.csNotesPage クラスのコードビハインド。ユーザーがページを操作したときに実行されるビジネス ロジックが含まれています。
  • Views\NoteEntryPage.xamlNoteEntryPage クラスの XAML マークアップ。ユーザーがメモを入力するときに表示されるページの UI が定義されています。
  • Views\NoteEntryPage.xaml.csNoteEntryPage クラスのコードビハインド。ユーザーがページを操作するときに実行されるビジネス ロジックが含まれています。
  • App.xaml: App クラスの XAML マークアップ。アプリケーションのリソース ディクショナリを定義します。
  • App.xaml.csApp クラスのコードビハインド。シェル アプリケーションのインスタンス化と、アプリケーションのライフサイクル イベントの処理が行われます。
  • AppShell.xamlAppShell クラスの XAML マークアップ。アプリケーションのビジュアル階層が定義されています。
  • AppShell.xaml.csAppShell クラスのコードビハインド。プログラムによって移動できるように、NoteEntryPage のルートが作成されます。
  • AssemblyInfo.cs – このファイルには、アセンブリ レベルで適用されるプロジェクトに関するアプリケーション属性が含まれています。

Xamarin.iOS アプリケーションの構造については、「Anatomy of a Xamarin.iOS Application」(Xamarin.iOS アプリケーションの構造) を参照してください。 Xamarin.Android アプリケーションの構造については、「Anatomy of a Xamarin.Android Application」(Xamarin.Android アプリケーションの構造) を参照してください。

アーキテクチャとアプリケーションの基礎

Xamarin.Forms アプリケーションは、従来のクロスプラットフォーム アプリケーションと同じ方法で設計されています。 通常、共有コードは .NET Standard ライブラリに配置され、プラットフォーム固有のアプリケーションは共有コードを使用します。 次の図は、Notes アプリケーションのこの関係の概要を示しています。

Notes Architecture

スタートアップ コードを最大限に再利用するため、Xamarin.Forms アプリケーションには App という名前の 1 つのクラスがあり、各プラットフォームでのアプリケーションのインスタンス化が行われます。次にコード例を示します。

using Xamarin.Forms;

namespace Notes
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
            MainPage = new AppShell();
        }
        // ...
    }
}

このコードにより、App クラスの MainPage プロパティが AppShell オブジェクトに設定されます。 AppShell クラスにより、アプリケーションのビジュアル階層が定義されます。 シェルによってこのビジュアル階層が取得されて、そのユーザー インターフェイスが生成されます。 アプリケーションのビジュアル階層を定義する方法の詳細については、「アプリケーションのビジュアル階層」を参照してください。

さらに、AssemblyInfo.cs ファイルには、アセンブリ レベルで適用される単一のアプリケーション属性が含まれています。

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

XamlCompilation 属性により XAML コンパイラが有効になるため、XAML は中間言語に直接コンパイルされます。 詳細については、「XAML Compilation」(XAML のコンパイル) を参照してください。

各プラットフォームでアプリケーションを起動する

各プラットフォームでのアプリケーションの起動方法は、プラットフォームによって異なります。

iOS

iOS で最初の Xamarin.Forms ページを起動するため、Notes.iOS プロジェクトでは FormsApplicationDelegate クラスを継承する AppDelegate クラスが定義されます。

namespace Notes.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            return base.FinishedLaunching(app, options);
        }
    }
}

FinishedLaunching オーバーライドは、Init メソッドを呼び出すことで Xamarin.Forms フレームワークを初期化します。 その結果、Xamarin.Forms の iOS 固有の実装がアプリケーションに読み込まれ、次に LoadApplication メソッドの呼び出しによってルート ビュー コントローラーが設定されます。

Android

Android で最初の Xamarin.Forms ページを起動するために、Notes.Android プロジェクトには、MainLauncher 属性が指定され、FormsAppCompatActivity クラスから継承したアクティビティがある Activity を作成するコードが含まれています。

namespace Notes.Droid
{
    [Activity(Label = "Notes",
              Icon = "@mipmap/icon",
              Theme = "@style/MainTheme",
              MainLauncher = true,
              ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
    }
}

OnCreate オーバーライドは、Init メソッドを呼び出すことで Xamarin.Forms フレームワークを初期化します。 それにより、Xamarin.Forms の Android 固有の実装がアプリケーションに読み込まれ、次に Xamarin.Forms アプリケーションが読み込まれます。

アプリケーションのビジュアル階層

Xamarin.Forms シェル アプリケーションでは、Shell クラスをサブクラス化するクラスで、アプリケーションのビジュアル階層が定義されています。 Notes アプリケーションの場合、これは Appshell クラスです。

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Notes.Views"
       x:Class="Notes.AppShell">
    <TabBar>
        <ShellContent Title="Notes"
                      Icon="icon_feed.png"
                      ContentTemplate="{DataTemplate views:NotesPage}" />
        <ShellContent Title="About"
                      Icon="icon_about.png"
                      ContentTemplate="{DataTemplate views:AboutPage}" />
    </TabBar>
</Shell>

この XAML は、次の 2 つの主要なオブジェクトで構成されます。

  • TabBarTabBar は下部のタブ バーを表し、アプリケーションのナビゲーション パターンで下部のタブを使用する場合は、これを使用する必要があります。 TabBar オブジェクトは、Shell オブジェクトの子です。
  • ShellContent は、TabBar の各タブの ContentPage オブジェクトを表します。 各 ShellContent オブジェクトは、TabBar オブジェクトの子です。

これらのオブジェクトは、ユーザー インターフェイスではなく、アプリケーションのビジュアル階層の編成を表しています。 シェルでは、これらのオブジェクトを取得して、コンテンツのナビゲーション ユーザー インターフェイスを生成します。 したがって、AppShell クラスにより、下部のタブから移動できる 2 つのページが定義されています。 ページは、ナビゲーションに応じて、オンデマンドで作成されます。

シェル アプリケーションの詳細については、「Xamarin.Forms シェル」を参照してください。

ユーザー インターフェイス

Xamarin.Forms アプリケーションのユーザー インターフェイスを作成するには、複数のコントロール グループが使用されます。

  1. ページ: Xamarin.Forms のページは、クロスプラットフォーム モバイル アプリケーション画面を表しています。 Notes アプリケーションでは、1 つの画面を表示するために ContentPage クラスが使用されます。 ページの詳細については、「Xamarin.Forms のページ」を参照してください。
  2. ビュー: Xamarin.Forms のビューは、ユーザー インターフェイスに表示されるコントロールで、ラベル、ボタン、テキスト入力ボックスなどです。 完成した Notes アプリケーションでは、CollectionViewEditorButton のビューが使用されます。 ビューの詳細については、「Xamarin.Forms のビュー」を参照してください。
  3. レイアウト: Xamarin.Forms のレイアウトは、ビューを論理構造にまとめるために使用されるコンテナーです。 Notes アプリケーションでは、ビューを垂直方向に並べて配置するために StackLayout クラスが使用され、ボタンを水平方向に配置するために Grid クラスが使用されます。 レイアウトの詳細については、「Xamarin.Forms のレイアウト」を参照してください。

実行時に、各コントロールはネイティブの同等のものにマップされます。そしてそれがレンダリングされます。

レイアウト

Notes アプリケーションでは、StackLayout を使用して、画面サイズにかかわらず、画面上のビューを自動的に配置することで、クロスプラットフォーム アプリケーションの開発が簡素化されます。 各子要素は、追加した順に、水平または垂直方向に 1 つずつ配置されます。 StackLayout が使用する領域の量は、HorizontalOptions プロパティと VerticalOptions プロパティの設定によって異なりますが、StackLayout は既定で全画面を使用しようとします。

次の XAML コードは、StackLayout を使用して NoteEntryPage をレイアウトする例を示しています。

<?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="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    ...    
    <StackLayout Margin="{StaticResource PageMargin}">
        <Editor Placeholder="Enter your note"
                Text="{Binding Text}"
                HeightRequest="100" />
        <Grid>
            ...
        </Grid>
    </StackLayout>    
</ContentPage>

既定では、StackLayout は垂直方向を前提としています。 ただし、StackLayout.Orientation プロパティを StackOrientation.Horizontal 列挙メンバーに設定することによって、水平方向に変更することができます。

Note

ビューのサイズは、HeightRequestWidthRequest のプロパティを使用して設定できます。

StackLayout クラスの詳細については、「Xamarin.Forms StackLayout」を参照してください。

ユーザー操作に対する応答

XAML に定義されているオブジェクトによって、分離コード ファイルで処理されるイベントが発生する可能性があります。 次のコード例は、[保存] ボタンによって発生する Clicked イベントに応答して実行される、NoteEntryPage クラスのコードビハインドの OnSaveButtonClicked メソッドを示しています。

async void OnSaveButtonClicked(object sender, EventArgs e)
{
    var note = (Note)BindingContext;
    note.Date = DateTime.UtcNow;
    if (!string.IsNullOrWhiteSpace(note.Text))
    {
        await App.Database.SaveNoteAsync(note);
    }
    await Shell.Current.GoToAsync("..");
}

OnSaveButtonClicked メソッドは、データベースにメモを保存し、前のページに戻ります。 ナビゲーションの詳細については、「ナビゲーション」を参照してください。

Note

XAML クラスの分離コード ファイルは、x:Name 属性を指定して割り当てられた名前を使用して、XAML に定義されているオブジェクトにアクセスできます。 この属性に割り当てられている値は、C# 変数と同じルールを持っています。つまり、英字またはアンダースコアから始まり、埋め込みスペースが含まれる必要があります。

保存ボタンから OnSaveButtonClicked メソッドに接続する処理は、NoteEntryPage クラスの XAML マークアップで発生します。

<Button Text="Save"
        Clicked="OnSaveButtonClicked" />

表示内容

CollectionView により、項目のコレクションがリストに表示されます。 既定では、リスト項目は垂直方向に表示され、各項目が 1 つの行に表示されます。

次のコード例は、NotesPage からの CollectionView を示しています。

<CollectionView x:Name="collectionView"
                Margin="{StaticResource PageMargin}"
                SelectionMode="Single"
                SelectionChanged="OnSelectionChanged">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical"
                           ItemSpacing="10" />
    </CollectionView.ItemsLayout>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                <Label Text="{Binding Text}"
                       FontSize="Medium" />
                <Label Text="{Binding Date}"
                       TextColor="{StaticResource TertiaryColor}"
                       FontSize="Small" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

CollectionView の各行のレイアウトは CollectionView.ItemTemplate 要素内で定義され、データ バインディングを使用して、アプリケーションによって取得されたすべてのメモが表示されます。 CollectionView.ItemsSource プロパティは、NotesPage.xaml.cs でデータ ソースに設定されています。

protected override async void OnAppearing()
{
    base.OnAppearing();

    collectionView.ItemsSource = await App.Database.GetNotesAsync();
}

このコードにより、データベースに格納されているすべてのメモが CollectionView に設定され、これはページが表示されるときに実行されます。

CollectionView で項目が選択されると、SelectionChanged イベントが発生します。 イベントが発生すると、OnSelectionChanged という名前のイベント ハンドラーが実行されます。

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // ...
    }
}

SelectionChanged イベントでは、e.CurrentSelection プロパティを使用することで、項目に関連付けられているオブジェクトにアクセスできます。

CollectionView クラスの詳細については、「Xamarin.Forms CollectionView」を参照してください。

ナビゲーションは、移動先の URI を指定して、シェル アプリケーション内で実行されます。 ナビゲーション URI には、3 つのコンポーネントがあります。

  • "ルート"。シェルの視覚階層の一部として存在するコンテンツへのパスを定義します。
  • "ページ"。 シェルの視覚階層に存在しないページは、シェル アプリケーション内の任意の場所からナビゲーション スタック上にプッシュできます。 たとえば、NoteEntryPage は、シェルのビジュアル階層では定義されていませんが、必要に応じてナビゲーション スタックにプッシュできます。
  • 1 つまたは複数の "クエリ パラメーター"。 クエリ パラメーターは、ナビゲーション中に移動先ページに渡すことができるパラメーターです。

ナビゲーション URI に 3 つのコンポーネントがすべて含まれる必要はありませんが、含まれている場合は //route/page?queryParameters という構造になります

Note

ルートは、Route プロパティを使用して、シェルのビジュアル階層内の要素で定義できます。 ただし、Route プロパティが設定されていない場合は (Notes アプリケーションなど)、実行時にルートが生成されます。

シェルのナビゲーションの詳細については、「Xamarin.Forms シェルのナビゲーション」を参照してください。

ルートを登録する

シェルのビジュアル階層に存在しないページに移動するには、最初にシェルのルーティング システムに登録する必要があります。 Routing.RegisterRoute メソッドを使用します。 Notes アプリケーションの場合、これは AppShell コンストラクターで行われます。

public partial class AppShell : Shell
{
    public AppShell()
    {
        // ...
        Routing.RegisterRoute(nameof(NoteEntryPage), typeof(NoteEntryPage));
    }
}

この例では、NoteEntryPage という名前のルートが、NoteEntryPage 型に登録されています。 このページには、URI ベースのナビゲーションを使用して、アプリケーション内の任意の場所から移動できます。

ナビゲーションを実行する

ナビゲーションは、移動先のルートを表す引数を受け取る GoToAsync メソッドによって実行されます。

await Shell.Current.GoToAsync("NoteEntryPage");

この例では、NoteEntryPage に移動します。

重要

シェルのビジュアル階層にないページに移動するときは、ナビゲーション スタックが作成されます。

ページに移動するときに、クエリ パラメーターとしてデータをページに渡すことができます。

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // Navigate to the NoteEntryPage, passing the ID as a query parameter.
        Note note = (Note)e.CurrentSelection.FirstOrDefault();
        await Shell.Current.GoToAsync($"{nameof(NoteEntryPage)}?{nameof(NoteEntryPage.ItemId)}={note.ID.ToString()}");
    }
}

この例では、CollectionView で現在選択されている項目を取得し、NoteEntryPage に移動します。Note オブジェクトの ID プロパティの値が、クエリ パラメーターとして NoteEntryPage.ItemId プロパティに渡されます。

渡されたデータを受け取るため、NoteEntryPage クラスは QueryPropertyAttribute で修飾されています

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }
    }
    // ...
}

QueryPropertyAttribute の最初の引数では、渡されたデータを ItemId プロパティで受け取ることが指定され、2 番目の引数ではクエリ パラメーター ID が指定されています。そのため、上の例にある QueryPropertyAttributeでは、GoToAsync メソッドの呼び出しにおいて URI から ItemIdクエリ パラメータ―に渡されたデータを ItemId プロパティが受信するように、指定しています。 その後、ItemId プロパティによって LoadNote メソッドが呼び出されて、デバイスからメモが取得されます。

".." を GoToAsync メソッドへの引数として指定すると、後方ナビゲーションが実行されます。

await Shell.Current.GoToAsync("..");

後方ナビゲーションの詳細については、「後方ナビゲーション」を参照してください。

データ バインディング

Xamarin.Forms アプリケーションがデータを表示し、相互作用するしくみを簡素化するために、データ バインディングが使用されます。 データ バインディングはユーザー インターフェイスと基礎アプリケーションの間で接続を確立します。 BindableObject クラスには、データ バインディングをサポートするためのインフラストラクチャの大部分が含まれています。

データ バインディングでは、ソースターゲットと呼ばれる 2 つのオブジェクトを接続します。 ソース オブジェクトはデータを提供します。 ターゲット オブジェクトは、ソース オブジェクトのデータを使用し (またしばしば表示し) ます。 たとえば、Editor ("ターゲット" オブジェクト) は一般的にその Text プロパティを "ソース" オブジェクトのパブリック プロパティ string にバインドします。 次の図では、バインドの関係を示します。

Data Binding

データ バインディングの主な利点は、ビューとデータ ソース間でデータを同期する心配がないことです。 ソース オブジェクトの変更は、バインディング フレームワークによって背後で自動的にターゲット オブジェクトにプッシュされます。そして、ターゲット オブジェクトの変更は、オプションでソース オブジェクトに戻されます。

データ バインディングを確立するには、次の 2 つの手順を実行します。

  • "ターゲット" オブジェクトの BindingContext プロパティは、"ソース" に設定する必要があります。
  • バインディングはターゲットソース間で確立する必要があります。 XAML でこれは、Binding マークアップ拡張を使用して実現できます。

Notes アプリケーションでは、 の NoteEntryPageBindingContext として設定された Note インスタンスがバインディング ソースであるのに対し、バインディング ターゲットはメモを表示する Editor です。 最初、ページ コンストラクターが実行されるときに、NoteEntryPageBindingContext が設定されます。

public NoteEntryPage()
{
    // ...
    BindingContext = new Note();
}

この例では、NoteEntryPage が作成されるときに、ページの BindingContext に新しい Note が設定されます。 これにより、アプリケーションに新しいメモを追加するシナリオが処理されます。

さらに、NotesPage で既存のメモが選択されている場合は、NoteEntryPage へのナビゲーションが発生したときにも、ページの BindingContext を設定できます。

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }

        async void LoadNote(string itemId)
        {
            try
            {
                int id = Convert.ToInt32(itemId);
                // Retrieve the note and set it as the BindingContext of the page.
                Note note = await App.Database.GetNoteAsync(id);
                BindingContext = note;
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to load note.");
            }
        }    
        // ...    
    }
}

この例では、ページ ナビゲーションが発生すると、選択されている Note オブジェクトがデータベースから取得されて、ページの BindingContext に設定されます。

重要

各 "ターゲット" オブジェクトの BindingContext プロパティは個々に設定できますが、必ずしもそうする必要はありません。 BindingContext は、その子がすべて継承する特殊なプロパティです。 したがって、ContentPageBindingContextNote インスタンスに設定された場合、ContentPage のすべての子は同じ BindingContext を持ち、Note オブジェクトのパブリック プロパティにバインドすることができます。

その後、NoteEntryPage 内の EditorNote オブジェクトの Text プロパティにバインドされます。

<Editor Placeholder="Enter your note"
        Text="{Binding Text}" />

"ソース" オブジェクトの Editor.Text プロパティと Text プロパティ間のバインディングが確立されます。 Editor での変更は Note オブジェクトに自動的に伝達されます。 同様に、Note.Text プロパティが変更された場合、Xamarin.Forms のバインド エンジンによって Editor のコンテンツも更新されます。 これは、双方向のバインドとも呼ばれています。

データ バインディングの詳細については、「Xamarin.Forms のデータ バインディング」を参照してください。

スタイル

Xamarin.Forms アプリケーションには、多くの場合、同じ外観を持つ複数のビジュアル要素が含まれています。 各ビジュアル要素の外観を設定すると、繰り返し使用しやすく、エラーが発生しやすくなります。 代わりに、外観を定義し、必要なビジュアル要素に適用するスタイルを作成できます。

Style クラスは、プロパティ値のコレクションを 1 つのオブジェクトにグループ化して、複数のビジュアル要素インスタンスに適用できるようにします。 スタイルは、アプリケーション レベル、ページ レベル、ビュー レベルのいずれかで ResourceDictionary に格納されます。 Style を定義する場所の選択は、それを使用できる場所に影響します。

  • アプリケーション レベルで定義された Style インスタンスは、アプリケーション全体に適用できます。
  • ページ レベルで定義された Style インスタンスは、ページとその子に適用できます。
  • ビュー レベルで定義された Style インスタンスは、ビューとその子に適用できます。

重要

アプリケーション全体で使用されるスタイルは、重複を回避するために、アプリケーションのリソース ディクショナリに保存されます。 ただし、あるページに固有の XAML は、アプリケーションのリソース ディクショナリに含めるべきではありません。アプリのリソースは、ページが必要とするときではなく、アプリケーションの起動時に解析されるためです。 詳細については、「アプリケーション リソース ディクショナリのサイズを減らす」を参照してください。

Style インスタンスには、1 つ以上の Setter オブジェクトのコレクションが含まれています。各 Setter には、PropertyValueがあります。 Property は、スタイルが適用される要素のバインド可能なプロパティの名前で、Value はプロパティに適用される値です。 次のコード例は、NoteEntryPage のスタイルを示しています。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    <ContentPage.Resources>
        <!-- Implicit styles -->
        <Style TargetType="{x:Type Editor}">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>
        ...
    </ContentPage.Resources>
    ...
</ContentPage>

このスタイルは、ページ上の任意の Editor インスタンスに適用されます。

Style を作成する場合は、TargetType プロパティが常に必要です。

Note

Xamarin.Forms アプリケーションのスタイル設定は、これまで XAML スタイルを使用して行われていました。 しかし Xamarin.Forms では、カスケード スタイル シート (CSS) を使用したビジュアル要素のスタイル設定もサポートされています。 詳細については、「カスケード スタイル シート (CSS) を使用した アプリのスタイル設定Xamarin.Forms」を参照してください。

XAML スタイルの詳細については、「XAML スタイルを使用した Xamarin.Forms アプリのスタイル設定」を参照してください。

テストと展開

Visual Studio for Mac と Visual Studio のいずれも、アプリケーションをテストおよび展開するためのオプションを多数用意しています。 アプリケーションのデバッグは、アプリケーション開発ライフサイクルの一般的な部分であり、コードの問題を診断するときに役立ちます。 詳細については、「Set a Breakpoint」(ブレークポイントの設定)、「Step Through Code」(コードのステップ スルー)、「Output Information to the Log Window」(ログ ウィンドウへの出力情報) を参照してください。

シミュレーターは、アプリケーションの展開とテストを始めるにはおすすめの場所です。また、テスト アプリケーションに役立つ機能があります。 ただし、ユーザーは完成したアプリケーションをシミュレーター上では使用しないので、早期に、そして何度も実際のデバイス上でアプリケーションをテストすることをお勧めします。 iOS デバイスのプロビジョニングの詳細については、「Device Provisioning」(デバイスのプロビジョニング) を参照してください。 Android デバイスのプロビジョニングの詳細については、「Set Up Device for Development」(開発用のデバイスの設定) を参照してください。

次の手順

この詳細では、Xamarin.Forms シェルを使用したアプリケーション開発の基礎について説明しました。 推奨される次の手順としては、次の機能の説明を読んでください。

  • Xamarin.Forms シェルでは、ほとんどのモバイル アプリケーションが必要としている基本機能を提供することで、モバイル アプリケーション開発の複雑さが軽減されます。 詳細は、「Xamarin.Forms シェル」を参照してください。
  • Xamarin.Forms アプリケーションのユーザー インターフェイスを作成するには、複数のコントロール グループが使用されます。 詳細については、「Controls Reference」 (コントロールのリファレンス) を参照してください。
  • データ バインディングは、2 つのオブジェクトのプロパティをリンクして、片方のプロパティでの変更が自動的にもう片方のプロパティに反映されるようにする手法です。 詳細については、データ バインディングに関するページを参照してください。
  • Xamarin.Forms には、使用されるページの種類に応じて、複数のページ ナビゲーション エクスペリエンスが用意されています。 詳細については、「ナビゲーション」を参照してください。
  • スタイルは、繰り返されるマークアップを減らすのに役立ち、アプリケーションの外観をより簡単に変更できるようにします。 詳細については、「Xamarin.Forms アプリのスタイル設定」を参照してください。
  • データ テンプレートでは、サポートされているビューでのデータの表現方法を定義する機能が提供されます。 詳細については、「Data Templates」 (データ テンプレート) を参照してください。
  • エフェクトでは、各プラットフォームのネイティブ コントロールのカスタマイズを可能にします。 エフェクトは、プラットフォーム固有のプロジェクトで PlatformEffect クラスをサブクラス化することによって作成され、適切な Xamarin.Forms コントロールに添付することによって使用されます。 詳細については、「Effects」 (エフェクト) を参照してください。
  • 各ページ、レイアウト、およびビューは Renderer クラスを使用して、プラットフォームごとに異なる方法でレンダリングされます。その後、ネイティブ コントロールが作成され、画面に配置され、共有コードで指定された動作が追加されます。 開発者は独自の Renderer クラスを実装して、コントロールの外観や動作をカスタマイズできます。 詳細については、「Custom Renderers」 (カスタム レンダラー) を参照してください。
  • 共有コードはネイティブ機能に DependencyService クラスを介してアクセスできます。 詳細については、「Accessing Native Features with DependencyService」 (DependencyService を使用したネイティブ機能へのアクセス) を参照してください。

他の Xamarin ビデオは、Channel 9 および YouTube でご覧いただけます。