XAMLの基本（Xamarin公式XAMLページ全訳）と基礎の入り口

# 概要

Xamarin.Formsを使ってアプリを開発するとき、UI作成にXAMLを使用する方は多いのではないでしょうか？僕もその1人です。

僕は開発時XAMLについて調べるとき、XAMLを「どのように」使うかについて触れた記事を読んできましたが、XAMLが「なぜ」そのように使えるのか、どういう仕組みで動いているのかについてはあまり考えてきませんでした。

そこでこの記事ではXAMLの「なぜ」や「基礎」の入り口になるような話を書きたいと思っています。基礎を徹底的に掘り下げるものでも、網羅するものでも、ありません。

付録として最後に「どのように」使うかが説明されたXamarin公式ページ[eXtensible Application Markup Language (XAML)](https://developer.xamarin.com/guides/xamarin-forms/xaml/)の全訳を載せます。とても長いですが、「基本」事項（使い方を）概観するにはぴったりの記事です。

# XAMLとは？
まず、XAMLとは何なのでしょうか？XamarinによるXamarin.Formsの公式ページでは次のように説明されています。

[eXtensible Application Markup Language (XAML)](https://developer.xamarin.com/guides/xamarin-forms/xaml/)

> XAML is a declarative markup language that can be used to define user interfaces. The user interface is defined in an XML file using the XAML syntax, while runtime behavior is defined in a separate code-behind file.

（訳）XAMLはユーザインターフェースを定義する宣言的なマークアップ言語です。ユーザインターフェースはXAML構文を用いてXMLファイル内で定義され、実行時のふるまいは別のコードビハインドファイル内で定義されます。

また、以前参加した勉強会等では次のようにも説明されていました。

[XAML入門 13 / 38 by Kazuki Ota さん](https://www.slideshare.net/okazuki0130/xaml-71503072)
> UI記述特化言語ではない　オブジェクトのインスタンスを組み立てるための言語

[XAML＆Application Platform ～これまでとこれから～ 9 / 56 by Shinobu Takahashi さん](https://www.slideshare.net/ssuser3c35a5/xamlapplication-platform)
> UIを定義するために特化した言語ではなく　オブジェクトのインスタンスとオブジェクト間の階層構造を構築する定義型言語

XAMLで定義した内容はUIとして活用されるけれど、その本質は「オブジェクトのインスタンスの構築」にあるということでしょうか。


## XAMLをコードで表現する
XAMLではこんな風に書きます。でも、これと同等の内容はC#のコードで表現できます。という説明を行う本を見たことがあります。例えばこのようなものです


```xml:XamlSamplePage.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"
  xmlns:local="clr-namespace:XamlSample"
  x:Class="XamlSample.XamlSamplePage">
	<Label Text="Welcome to Xamarin Forms!" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>
```


```csharp:XamlSamplePage.xaml.cs
using Xamarin.Forms;

namespace XamlSample
{
    public partial class XamlSamplePage : ContentPage
    {
        public XamlSamplePage()
        {
            InitializeComponent();
        }
    }
}
```

の組み合わせと、単独の

```csharp:XamlSamplePage.xaml.cs
using Xamarin.Forms;

namespace XamlSample
{
    public partial class XamlSamplePage : ContentPage
    {
        public XamlSamplePage()
        {
            Content = new Label
            {
                Text = "Welcome to Xamarin Forms!",
                VerticalOptions = LayoutOptions.Center,
                HorizontalOptions = LayoutOptions.Center
            };
        }
    }
}
```

は実行したときに表示されるのはいずれも次のスクリーンショットのようになります。

<img src="https://user-images.githubusercontent.com/7035446/33801200-a2cc4dea-dd96-11e7-84c4-2125ad4539a5.png" title="Welcome to Xamarin Forms" alt="Welcome to Xamarin Forms" width="40%">

ここで、もしかしたらXAML定義からC#コードに変換しているのではないか？`InitializeComponent()`が大事な機能を果たしているのではないか？という考えが頭をよぎります。

どのタイミングで、なにが、どうやってXAML定義を使用するのでしょうか？

# XAMLG
ここで登場するのがXAMLGタスクです。

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Build.Tasks/XamlGTask.cs

Xamarin.Formsの新規プロジェクトを作成し、上記のXAMLとコードビハインドを準備してビルドしてみましょう。

`XamlSample/obj/Debug`内に生成された成果物を探すと次のようなファイルを見つけることができます。


```csharp:XamlSample.XamlSamplePage.xaml.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace XamlSample {
    
    
    [global::Xamarin.Forms.Xaml.XamlFilePathAttribute("/Users/sugita-toshinori/dev/codes/xamarin/XamlSample/XamlSample/XamlSamplePage.xa" +
        "ml")]
    public partial class XamlSamplePage : global::Xamarin.Forms.ContentPage {
        
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
        private void InitializeComponent() {
            global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(XamlSamplePage));
        }
    }
}
```

`InitializeComponent`メソッドが定義されており、`LoadFromXaml`が何かを行なってくれそうです。

これはどこに定義されていて、何を行なっているのでしょうか？

メソッドの詳細を追う前に、このメソッドが呼ばれるまでの大まかな流れを確認しましょう。

先ほども言及したXamarin公式ページでは次のように処理フローが説明されています。

> At runtime, code in the particular platform project calls a LoadApplication method, passing to it a new instance of the App class in the PCL. The App class constructor instantiates XamlSamplesPage. The constructor of that class calls InitializeComponent, which then calls the LoadFromXaml method that extracts the XAML file (or its compiled binary) from the PCL. LoadFromXaml initializes all the objects defined in the XAML file, connects them all together in parent-child relationships, attaches event handlers defined in code to events set in the XAML file, and sets the resultant tree of objects as the content of the page.

（訳）実行時に、特定のプラットフォームプロジェクトのコードが**LoadApplication**メソッドを呼び出し、PCLの**App**クラスの新しいインスタンスをそのクラスに渡します。**App**クラスのコンストラクタは、**XamlSamplesPage**をインスタンス化します。そのクラスのコンストラクタは**InitializeComponent**を呼び出し、次に、XAMLファイル（またはそのコンパイルされたバイナリ）をPCLから抽出する**LoadFromXaml**メソッドを呼び出します。**LoadFromXaml**は、XAMLファイルで定義されているすべてのオブジェクトを初期化し、それらをすべて親子関係で接続し、コードで定義されているイベントハンドラをXAMLファイルに設定されたイベントに関連付け、オブジェクトのツリーをページのコンテンツとして設定します。

これまで追ってきたように、ページをインスタンス化する際、コンストラクタで`InitializeComponent`を呼び出し、`LoadFromXaml`で**XAMLで定義されたすべてのオブジェクトを初期化**するというのは仮説からも離れていなさそうです。

それでは、`LoadFromXaml`の定義を探してみましょう。

ここにありました。

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml/ViewExtensions.cs

```csharp:ViewExtensions.cs
using System;

namespace Xamarin.Forms.Xaml
{
	public static class Extensions
	{
		public static TXaml LoadFromXaml<TXaml>(this TXaml view, Type callingType)
		{
			XamlLoader.Load(view, callingType);
			return view;
		}

		internal static TXaml LoadFromXaml<TXaml>(this TXaml view, string xaml)
		{
			XamlLoader.Load(view, xaml);
			return view;
		}
	}
}
```

`XamlLoader.Load`で処理を行なっていそうです。また探してみましょう。

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml/XamlLoader.cs

```csharp:XamlLoader.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;
using Xamarin.Forms.Internals;

// （略）

namespace Xamarin.Forms.Xaml
{
	static class XamlLoader
	{
		public static void Load(object view, Type callingType)
		{
			var xaml = GetXamlForType(callingType);
			if (string.IsNullOrEmpty(xaml))
				throw new XamlParseException(string.Format("No embeddedresource found for {0}", callingType), new XmlLineInfo());
			Load(view, xaml);
		}

		public static void Load(object view, string xaml)
		{
			using (var textReader = new StringReader(xaml))
			using (var reader = XmlReader.Create(textReader))
			{
				while (reader.Read())
				{
					//Skip until element
					if (reader.NodeType == XmlNodeType.Whitespace)
						continue;
					if (reader.NodeType == XmlNodeType.XmlDeclaration)
						continue;
					if (reader.NodeType != XmlNodeType.Element) {
						Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
						continue;
					}

					var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), view, (IXmlNamespaceResolver)reader);
					XamlParser.ParseXaml (rootnode, reader);
					Visit (rootnode, new HydrationContext {
						RootElement = view,
#pragma warning disable 0618
						ExceptionHandler = ResourceLoader.ExceptionHandler ?? (Internals.XamlLoader.DoNotThrowOnExceptions ? e => { }: (Action<Exception>)null)
#pragma warning restore 0618
					});
					break;
				}
			}
		}

        // （略）
    }

```

`XmlReader`でXMLの各ノードを`While`でループしていく際に`XamlParser.ParseXaml (rootnode, reader)`しているのが気になります。

引数の`rootnode`には1行手前で`view`（ここでの実体は`XamlSamplePage`のインスタンス）が渡されているので、XAMLの構造をViewのツリー構造にマッピングしているのではないかと想像できます。

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml/XamlParser.cs

```csharp:XamlParser.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Xaml
{
	static class XamlParser
	{
		public const string XFUri = "http://xamarin.com/schemas/2014/forms";
		public const string X2006Uri = "http://schemas.microsoft.com/winfx/2006/xaml";
		public const string X2009Uri = "http://schemas.microsoft.com/winfx/2009/xaml";
		public const string McUri = "http://schemas.openxmlformats.org/markup-compatibility/2006";

		public static void ParseXaml(RootNode rootNode, XmlReader reader)
		{
			IList<KeyValuePair<string, string>> xmlns;
			var attributes = ParseXamlAttributes(reader, out xmlns);
			var prefixes = PrefixesToIgnore(xmlns);
			(rootNode.IgnorablePrefixes ?? (rootNode.IgnorablePrefixes=new List<string>())).AddRange(prefixes);
			rootNode.Properties.AddRange(attributes);
			ParseXamlElementFor(rootNode, reader);
		}

		static void ParseXamlElementFor(IElementNode node, XmlReader reader)
		{
			Debug.Assert(reader.NodeType == XmlNodeType.Element);

			var elementName = reader.Name;
			var isEmpty = reader.IsEmptyElement;

			if (isEmpty)
				return;

			while (reader.Read())
			{
				switch (reader.NodeType)
				{
					case XmlNodeType.EndElement:
						Debug.Assert(reader.Name == elementName); //make sure we close the right element
						return;
					case XmlNodeType.Element:
						// 1. Property Element.
						if (reader.Name.Contains("."))
						{
							XmlName name;
							if (reader.Name.StartsWith(elementName + ".", StringComparison.Ordinal))
								name = new XmlName(reader.NamespaceURI, reader.Name.Substring(elementName.Length + 1));
							else //Attached DP
								name = new XmlName(reader.NamespaceURI, reader.LocalName);

							var prop = ReadNode(reader);
							if (prop != null)
								node.Properties.Add(name, prop);
						}
						// 2. Xaml2009 primitives, x:Arguments, ...
						else if (reader.NamespaceURI == X2009Uri && reader.LocalName == "Arguments")
						{
							var prop = ReadNode(reader);
							if (prop != null)
								node.Properties.Add(XmlName.xArguments, prop);
						}
						// 3. DataTemplate (should be handled by 4.)
						else if (node.XmlType.NamespaceUri == XFUri &&
						         (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate"))
						{
							var prop = ReadNode(reader, true);
							if (prop != null)
								node.Properties.Add(XmlName._CreateContent, prop);
						}
						// 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later.
						else
						{
							var item = ReadNode(reader, true);
							if (item != null)
								node.CollectionItems.Add(item);
						}
						break;
					case XmlNodeType.Whitespace:
						break;
					case XmlNodeType.Text:
					case XmlNodeType.CDATA:
						if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode)
							((ValueNode)node.CollectionItems[0]).Value += reader.Value.Trim();
						else
							node.CollectionItems.Add(new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader));
						break;
					default:
						Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
						break;
				}
			}
		}

        // （省略）
    }
}
```

`ParseXamlElementFor`で`NodeType`毎にnode（`rootNode`）への追加の仕方が振り分けられています。

この`XamlParser.ParseXaml`で整理された要素は、先ほど見た`XamlLoader.Load`内の次の`Visit`メソッドでクラスとして`view`にセットされています。（急に雑）


答え合わせという訳でもありませんが、以下のUnit Testを見ることで、`LoadFromXaml`への入力と関数を実行した結果へのイメージがより具体的になると思います。

こちらのテストなんていかがでしょうか？

インスタンス化した`ContentPage`にXamlを渡してUIを組み立てています。

ブレークポイントを貼ってデバッグ実行すると、過程がより追いやすいです。

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml.UnitTests/LoaderTests.cs

```csharp:LoaderTests.cs
 // （省略）
[Test]
		public void TestBindingModeAndConverter ()
		{
			var xaml = @"
				<ContentPage 
				xmlns=""http://xamarin.com/schemas/2014/forms""
				xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
				xmlns:local=""clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests"">
					<ContentPage.Resources>
						<ResourceDictionary>
							<local:ReverseConverter x:Key=""reverseConverter""/>
						</ResourceDictionary>
					</ContentPage.Resources>
					<ContentPage.Content>
						<StackLayout Orientation=""Vertical"">
							<StackLayout.Children>
								<Label x:Name=""label0"" Text=""{Binding Text, Converter={StaticResource reverseConverter}}""/>
								<Label x:Name=""label1"" Text=""{Binding Text, Mode=TwoWay}""/>
							</StackLayout.Children>
						</StackLayout>
					</ContentPage.Content>
				</ContentPage>";

			var contentPage = new ContentPage ();
			contentPage.LoadFromXaml (xaml);
			contentPage.BindingContext = new ViewModel { Text = "foobar" };
			var label0 = contentPage.FindByName<Label> ("label0");
			var label1 = contentPage.FindByName<Label> ("label1");
			Assert.AreEqual ("raboof", label0.Text);
	
			label1.Text = "baz";
			Assert.AreEqual ("baz", ((ViewModel)(contentPage.BindingContext)).Text);
		}
// （省略）
```

こちらはObsoleteなメソッド向けですね。
https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml.UnitTests/XamlLoaderCreateTests.cs

```csharp:XamlLoaderCreateTests.cs
 // （省略）
[TestFixture]
	public class XamlLoaderCreateTests
	{
		[Test]
		public void CreateFromXaml ()
		{
			var xaml = @"
				<ContentView xmlns=""http://xamarin.com/schemas/2014/forms""
							 xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
						 	 x:Class=""Xamarin.Forms.Xaml.UnitTests.FOO"">
					<Label Text=""Foo""  x:Name=""label""/>
				</ContentView>";

			var view = XamlLoader.Create (xaml);
			Assert.That (view, Is.TypeOf<ContentView> ());
			Assert.AreEqual ("Foo", ((Label)((ContentView)view).Content).Text);
		}
// （省略）
```

一度このように追っておくと、`InitializeComponent`が見つからないようなエラーのときは`InitializeComponent`定義が想定通りの名前空間に生成されているか、`InitializeComponent`の前にXAMLで定義したコントロールにアクセスしようとしても無理などこれまで遭遇したかもしれないエラーを避けることができます。

また「使い方」として説明されていたことが実装としてどう実現されているのかがだいぶしっくりくるかもしれません。

付録は次のような「使い方」を説明する記事です。

* XAMLの構文
* マークアップ拡張
* データバインディング
* MVVM触り
* XAMLコンパイル
* XAML名前空間
* バインダブルプロパティ
* 添付プロパティ
* リソースディクショナリー
* XAML Standard

Xamarin.Formsリポジトリを登場するキーワードを検索するともちろん引っかかるので興味がある方は追ってみてください。

# XAMLC
なんで実行時にXAMLを読み込むんだろう？先にコンパイルしておけばより高速にUIを表示できるのではないか？と考える人もいるかもしれません。

そこで XAMLCの登場です。

公式ページでは次のように説明されています。

> XAML can be optionally compiled directly into intermediate language (IL) with the XAML compiler (XAMLC).

> XAMLC offers a number of a benefits:

> It performs compile-time checking of XAML, notifying the user of any errors.
It removes some of the load and instantiation time for XAML elements.
It helps to reduce the file size of the final assembly by no longer including .xaml files.
XAMLC is disabled by default to ensure backwards compatibility. It can be enabled at both the assembly and class level by adding the XamlCompilation attribute.


（訳）XAMLは、XAMLコンパイラ（XAMLC）で中間言語（IL）に直接コンパイルすることもできます。

XAMLCには多くの利点があります。

* XAMLのコンパイル時チェックを実行し、ユーザーにエラーを通知します。
* XAML要素のロードおよびインスタンス化時間の一部を削減します。
* .xamlファイルを含まなくなることで、最終アセンブリのファイルサイズを縮小するのに役立ちます。

下位互換性を確保するため、XAMLCはデフォルトで無効になっています。**XamlCompilation**属性を追加することで、アセンブリレベルとクラスレベルの両方で有効にすることができます。


続きも翻訳しているので、気になる方はチェックしてみてください。

プレビュー版としてこの機能がリリースされたときに書かれたQiita記事では実行時にXAMLを読み込みUIを構築するケースとC#コードだけでUIを構築するケースとの比較記事もあり興味深いです。

[[Xamarin.Forms 1.5.1-pre1] XamlC (XAMLプリコンパイル)
](https://qiita.com/P3PPP/items/b70e75c6a796100436a5)

タスク本体はこのあたりを追ってください。
https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Build.Tasks/XamlCTask.cs

# その他
XAMLの基礎を追っていくと、いつかは自作のプレビューアなどに行き着くのではないか…という期待を込めてこの記事のリンクを貼っておきます。

[Xamarin.Forms 用のプレビューアをアルファ版で公開](http://www.moonmile.net/blog/archives/6030)


# 感想
色々遠回り（次に紹介する日本語訳とか…）した割に、自分が知りたかったことの入り口は

* コンパイルしたときにできる成果物を見る
* フレームワークやビルドタスクの関連しそうなソースコードを追う

をやるだけだったのが教訓的だったなぁと思いました。コード追いきれてないところはありつつ…。


動作の原理を追いたいときに必ずしもコード読めば自明ということばかりではないと思います。

でも人が説明する文章追ってばかりいないで、もう少し目の前で動いているコードを動かして仮説を作ったり、直接的に答えにたどりつくためのアプローチとっていかないと効率悪いなぁと書きながら反省しっぱなしでした。



# 付録: [Xamarin公式XAMLドキュメントの全訳](https://developer.xamarin.com/guides/xamarin-forms/xaml/)

## eXtensible Application Markup Language (XAML)

XAMLはユーザインターフェースを定義する宣言的なマークアップ言語です。ユーザインターフェースはXAML構文を用いてXMLファイル内で定義され、実行時のふるまいは別のコードビハインドファイル内で定義されます。

| タイトル<br>（アンカーリンク）　 | 元ページURL | 概要 |
|:----- |:----|:----|
| [XAMLの基本](#xamarinformsのxamlの基本)　　|https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/ | XAMLを使用すると、開発者はコードではなくマークアップを使用してXamarin.Formsアプリケーションでユーザインターフェースを定義できます。XAMLはXamarin.Formsプログラムでは必須ではなく、ツールのように使用できます。視覚的に一貫性があり、同等のコードよりも簡潔であることがよくあります。XAMLは、一般的なModel-View-ViewModel（MVVM）アプリケーションアーキテクチャでの使用に特に適しています。XAMLは、XAMLベースのデータバインディングを介してViewModelコードにリンクされたビューを定義します。|
| [XAMLコンパイル](#xamlコンパイル)　　　　　　 | https://developer.xamarin.com/guides/xamarin-forms/xaml/xamlc/ | XAMLは、XAMLコンパイラ（XAMLC）で中間言語（IL）に直接コンパイルすることもできます。この記事では、XAMLCの使用方法と利点について説明します。 |
| [XAMLプレビューア](#xamarinforms向けのxamlプレビューア) | https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/ | Xamarin Evolve 2016で発表されたXAMLプレビューアは、Alphaチャンネルでのテストに使用できます。|
| [XAML名前空間](#xaml名前空間)　 | https://developer.xamarin.com/guides/xamarin-forms/xaml/namespaces/ | XAMLは、名前空間宣言にxmlns XML属性を使用します。この記事では、XAML名前空間の構文を紹介し、型にアクセスするためにXAML名前空間を宣言する方法を示します。|
| [引数の受け渡し](#xamlでの引数の受け渡し) | https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/ | XAMLを使用すると、デフォルトでないコンストラクタやファクトリメソッドに引数を渡すことができます。この記事では、コンストラクタに引数を渡したり、ファクトリメソッドを呼び出したり、ジェネリックな引数の型を指定するために使用できるXAML属性の使用方法について説明します。|
| [バインダブルプロパティ](#バインダブルプロパティ) | https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/ | Xamarin.Formsでは、共通言語ランタイム（CLR）プロパティの機能がバインダブルプロパティによって拡張されています。バインダブルプロパティは特殊なタイプのプロパティです。プロパティの値はXamarin.Formsプロパティシステムによって追跡されます。この記事では、バインダブルプロパティの概要を紹介し、バインダブルプロパティを作成および使用する方法を示します。|
| [添付プロパティ](#添付プロパティ-) | https://developer.xamarin.com/guides/xamarin-forms/xaml/attached-properties/ | 添付プロパティはバインダブルプロパティの特殊な型であり、1つのクラスで定義されていますが他のオブジェクトに関連付けられています。XAMLでは、クラスとプロパティ名がピリオドで区切られた属性として認識されます。この記事では、添付プロパティの概要を説明し、それらを作成および使用する方法を示します。 |
| [リソースディクショナリー](#リソースディクショナリー) | https://developer.xamarin.com/guides/xamarin-forms/xaml/resource-dictionaries/ | XAMLリソースは、複数回使用できるオブジェクトの定義です。リソースディクショナリーを使用すると、リソースを単一の場所に定義し、Xamarin.Formsアプリケーション全体で再利用することができます。この資料では、リソースディクショナリーを作成および使用する方法と、リソースディクショナリーを別のリソースディクショナリーにマージする方法について説明します。 |

# [Xamarin.FormsのXAMLの基本](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/)

**モバイルデバイス向けのクロスプラットフォームマークアップを始める**

XAML（eXtensible Application Markup Language）を使用すると開発者はコードではなくマークアップを使用して、Xamarin.Formsアプリケーションでユーザインターフェースを定義できます。XAMLはXamarin.Formsプログラムでは必須ではなく、ツールのように使用できます。視覚的に一貫性があり、同等のコードよりも簡潔であることがよくあります。XAMLは、一般的なModel-View-ViewModel（MVVM）アプリケーションアーキテクチャでの使用に特に適しています。XAMLは、XAMLベースのデータバインディングを介してViewModelコードにリンクされたビューを定義します。

## XAMLの基本のコンテンツ

* 概要
* [パート1 XAML入門](#パート1-xaml入門)
* [パート2 XAML構文の本質](#パート2-xaml構文の本質)
* [パート3 XAMLマークアップ拡張](#パート3-xamlマークアップ拡張)
* [パート4 データバインディングの基礎](#パート4-データバインディングの基礎)
* [パート5 データバインディングからMVVMへ](#パート5-データバインディングからmvvmへ)

XAMLの基本記事に加え、以下の本の各章をダウンロードできます。
[Creating Mobile Apps with Xamarin.Forms Book](https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/)

* 第7章 XAMLとコード
* 第8章 コードとXAMLの調和
* 第10章 XAMLマークアップ拡張
* 第18章 MVVM

### 概要
XAMLは、オブジェクトのインスタンス化と初期化、および親子階層内でのオブジェクトの整理のためのプログラミングコードの代替としてMicrosoftによって開発されたXMLベースの言語です。XAMLは.NETフレームワーク内のいくつかのテクノロジに採用されていますが、とりわけWindows Presentation Foundation（WPF）、Silverlight、WindowsRuntime、ユニバーサルWindowsプラットフォーム（UWP）内のユーザインターフェースのレイアウトを定義する上で大きな役割を果たしています 。

XAMLは、iOS、Android、およびUWPモバイルデバイス用のクロスプラットフォームネイティブベースのプログラミングインターフェースであるXamarin.Formsの一部です。Xamarin.Formsの開発者は、XAMLファイル内で、すべてのXamarin.Formsビュー、レイアウト、ページ、およびカスタムクラスを使用してユーザインターフェースを定義できます。XAMLファイルは、コンパイルするか、実行可能ファイルに埋め込むことができます。どちらの方法でも、XAML情報はビルド時に名前付きオブジェクトの検索、実行時にオブジェクトのインスタンス化と初期化、およびこれらのオブジェクトとプログラミングコード間のリンクを確立するために解析されます。

XAMLには、同等のコードに比べていくつかの利点があります。

* XAMLは、同等のコードよりも簡潔で読みやすいことがよくあります。
* XML固有の親子階層により、XAMLはユーザインターフェースオブジェクトの親子階層をより明確に視覚化することができます。
* XAMLはプログラマが簡単に手書きすることができますが、視覚的なデザインツールでツールを作成して生成することもできます。

もちろん、主にマークアップ言語に内在する制限に関連する欠点もあります。

* XAMLにはコードを含めることはできません。すべてのイベントハンドラは、コードファイルで定義する必要があります。
* XAMLには繰り返し処理のループを含めることはできません。（ただし、ListViewなどのいくつかのXamarin.Formsビジュアルオブジェクトでは、ItemsSourceコレクション内のオブジェクトに基づいて複数の子を生成できます）
* XAMLには条件付き処理を含めることはできません。（ただし、データバインディングは、条件付き処理を効果的に行えるようにするコードベースのバインディングコンバーターを参照できます）
* XAMLは通常、パラメータのないコンストラクタを定義しないクラスはインスタンス化できません。（しかし、この制限を回避する方法があることもあります）
* XAMLは一般的にメソッドを呼び出すことはできません。（この場合も、制限を克服できることがあります）

Xamarin.FormsアプリケーションでXAMLを生成するビジュアルデザイナーはまだありません。すべてのXAMLは手書きでなければなりませんが、XAMLプレビューアがあります。XAMLを初めて使用するプログラマは、特に明らかには正しくないアプリケーションを実行した後に、頻繁にアプリケーションをビルドして実行したいかもしれません。XAMLの多くの経験を持つ開発者でさえ、実験は報われることでしょう。

XAMLは基本的にXMLですが、XAMLには独自の構文機能があります。最も重要なものは次のとおりです。

* プロパティ要素
* 添付プロパティ
* マークアップ拡張

これらの機能はXML拡張ではありません。XAMLは完全に法的なXMLです。しかし、これらのXAML構文機能はXMLを独自の方法で使用します。詳細は、以下の記事で説明します。これについてははMVVMを実装するためのXAMLの使用についての紹介があります。

### 要件
この記事では、Xamarin.Formsに精通していることを前提としています。An Introduction to Xamarin.Forms（リンク貼る）を読むことを強くお勧めします。

この記事では、XML名前空間宣言の使用方法、要素、タグ、属性という用語の理解を含む、XMLへのある程度の慣れを想定しています。
Xamarin.FormsとXMLに精通しているときは、第1部「XAML入門」を読んでください。

## [パート1 XAML入門](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/)

**要素と属性を持つページの定義**

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

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

Visual Studio for Macで、メニューから**File** > **New Solution**を選択します。**New Project**ダイアログで、左側にある**Multiplatform** > **App**を選択し、テンプレートリストから**Blank Forms App**（**Forms App**ではありません）を選択します。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/mac/NewProjectDialog1.png" title="New Project Dialog 1" alt="New Project Dialog 1" width="60%">

**Next**をクリックします。

次のダイアログで、プロジェクトに**XamlSamples**（または好きなもの）の名前を付けます。**Use Portable Class Library**ラジオボタンが選択されていること、**Use XAML for user interface files**チェックボックスがオンになっていることを確認します。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/mac/NewProjectDialog2.png" title="New Project Dialog 2" alt="New Project Dialog 2" width="60%">

**Next**をクリックします。

次のダイアログではプロジェクトの場所を選択できます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/mac/NewProjectDialog3.png" title="New Project Dialog 3" alt="New Project Dialog 3" width="60%">

**Create**をクリックします。

このソリューションには、**XamlSamples**ポータブルクラスライブラリ（PCL）、**XamlSamples.Android**、**XamlSamples.iOS**の3つのプロジェクトが作成されています。

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

プラットフォーム固有のコードを記述する必要がない限り、共有の**XamlSamples** PCLプロジェクトはプログラミング時間をほとんど費やす場所です。これらの記事は、そのプロジェクトの外の話はしません。

### XAMLファイルの構造
**XamlSamples**ポータブルクラスライブラリには、次の名前のファイルがあります。

* XAMLファイルである **App.xaml**
* XAMLファイルに関連付けられたC#コードビハインドファイルである**App.xaml.cs**

コードビハインドファイルを表示するには、**App.xaml**の横にある矢印をクリックする必要があります。

**App.xaml**と**App.xaml.cs**の両方が、**Application**から派生した**App**という名前のクラスに寄与します。XAMLファイルを持つ他のほとんどのクラスは、**ContentPage**から派生したクラスに寄与します。これらのファイルはXAMLを使用してページ全体のビジュアルコンテンツを定義します。これは、**XamlSamples**プロジェクトの他の2つのファイルにも当てはまります。

* XAMLファイルである **XamlSamplesPage.xaml**
* XAMLファイルに関連付けられたC#コードビハインドファイルである**XamlSamplesPage.xaml.cs**

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

```xml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.XamlSamplesPage">

    <Label Text="Welcome to Xamarin Forms!"
           VerticalOptions="Center"
           HorizontalOptions="Center" />

</ContentPage>
```

2つのXML名前空間（**xmlns**）宣言は、URIを参照しています。最初はXamarinのWebサイトに、もう1つはMicrosoftのものです。これらのURIが指しているものを確認する必要はありません。そこには何もありません。これらは単純にXamarinとMicrosoftが所有するURIであり、基本的にはバージョン識別子として機能します。

最初のXML名前空間宣言は、XAMLファイル内でプレフィックスなしで定義されたタグがXamarin.Formsのクラス（たとえば**ContentPage**）を参照することを意味します。2番目の名前空間宣言はプレフィックス**x**を定義します。これは、XAML自体に固有でXAMLの他の実装でサポートされているいくつかの要素と属性に対して使用されます。ただし、これらの要素と属性は、URIに埋め込まれた年によって少し異なります。Xamarin.Formsは2009 XAML仕様をサポートしていますが、そのすべてはサポートしていません。

**local**名前空間宣言により、PCLプロジェクトから他のクラスにアクセスすることができます。

最初のタグの最後の部分で、xプレフィックスが**Class**という名前の属性に使用されます。このxプレフィックスの使用はXAML名前空間では事実上共通しているため、**Class**などのXAML属性はほとんどの場合**x:Classと**呼ばれます。

**x:Class**属性は、完全修飾された.NETクラス名、つまり**XamlSamples**名前空間の**XamlSamplesPage**クラスを指定します。つまり、このXAMLファイルは、**x:Class**属性が表示されるタグであるContentPageから派生した**XamlSamples**名前空間に**XamlSamplesPage**という名前の新しいクラスを定義します。

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

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

```csharp
using Xamarin.Forms;

namespace XamlSamples
{
    public partial class XamlSamplesPage : ContentPage
    {
        public XamlSamplesPage()
        {
            InitializeComponent();
        }
    }
}
```

**XamlSamplesPage**クラスは**ContentPage**から派生していますが、**partial**クラス定義に注目してください。**XamlSamplesPage**の別のpartialクラス定義を持つ別のC#ファイルがあるはずですが、どこでしょうか？そして**InitializeComponent**メソッドとは何でしょうか？

Visual Studio for Macがプロジェクトをビルドすると、XAMLファイルが解析されてC#コードファイルが生成されます。**XamlSamples\XamlSamples\obj\Debug**ディレクトリを見ると、**XamlSamples.XamlSamplesPage.xaml.g.cs**という名前のファイルがあります。'g'は生成されたという意味です。これは、**XamlSamplesPage**コンストラクタから呼び出された**InitializeComponent**メソッドの定義を含む**XamlSamplesPage**の他の部分クラス定義です。これらの2つの**XamlSamplesPage**部分クラス定義はまとめてコンパイルされます。XAMLがコンパイルされているかどうかによって、XAMLファイルまたはバイナリ形式のXAMLファイルが実行可能ファイルに埋め込まれます。

実行時に、特定のプラットフォームプロジェクトのコードが**LoadApplication**メソッドを呼び出し、PCLの**App**クラスの新しいインスタンスをそのクラスに渡します。**App**クラスのコンストラクタは、**XamlSamplesPage**をインスタンス化します。そのクラスのコンストラクタは**InitializeComponent**を呼び出し、次に、XAMLファイル（またはそのコンパイルされたバイナリ）をPCLから抽出する**LoadFromXaml**メソッドを呼び出します。**LoadFromXaml**は、XAMLファイルで定義されているすべてのオブジェクトを初期化し、それらをすべて親子関係で接続し、コードで定義されているイベントハンドラをXAMLファイルに設定されたイベントに関連付け、オブジェクトのツリーをページのコンテンツとして設定します。

生成されたコードファイルでは通常は時間を費やす必要はありませんが、生成されたファイルのコードでは実行時の例外が発生することがあります。

このプログラムをコンパイルして実行すると、XAMLが示唆するように、Label要素がページの中央に表示されます。左からiOS、Android、Windows 10 Mobileです。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/XamlSamples.png" title="Default Xamarin.Forms display" alt="Default Xamarin.Forms display" width="60%">

より興味深いビジュアルを得るには、もっと興味深いXAMLが必要です。

### 準備
Windows用のVisual Studioで作成されたファイルとVisual Studio for Macでファイル名を一致させるには、**XamlSamplesPage.xaml**の名前を**MainPage.xaml**に、**XamlSamplesPage.xaml.cs**の名前を**MainPage.xaml.cs**に変更します。**XamlSamplesPage.xaml**ファイル内で、**XamlSamplesPage**を**MainPage**に変更します。XamlSamplesPage.xaml.csファイル内で、2回出現する**XamlSamplesPage**を**MainPage**に変更します。
**App.xaml.cs**ファイル内で、宣言を変更します。

```csharp
MainPage = new XamlSamplesPage();
```
↓

```csharp
MainPage = new MainPage();
```

続行する前に、プログラムがコンパイルおよびデプロイされることをテストします。

### 新しいXAMLページの追加
他のXAMLベースの**ContentPage**クラスをプロジェクトに追加するには、**XamlSamples** PCLプロジェクトを選択し、**File** > **New File**メニュー項目を呼び出します。**New File**ダイアログの左にある**Forms**を選択し、**Forms ContentPage Xaml**（コード・オンリー・ページを作成する**Forms ContentPage**でもページではない**Content View**でもありません）を選択します。ページに名前を付けます（例：**HelloXamlPage**）。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/mac/NewFileDialog.png" title="New File Dialog" alt="New File Dialog" width="60%">

**HelloXamlPage.xaml**とコードビハインドファイル**HelloXamlPage.xaml.cs**の2ファイルがプロジェクトに追加されます。

### ページコンテンツの設定
唯一のタグがContentPageとContentPage.Contentのタグであるように、HelloXamlPage.xamlファイルを編集します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage">
    <ContentPage.Content>

    </ContentPage.Content>
</ContentPage>
```

**ContentPage.Content**タグは、XAMLの一意の構文の一部です。最初は、無効なXMLと思われるかもしれませんが、有効です。ピリオドはXMLでは特殊文字ではありません。

**ContentPage.Content**タグは、*プロパティ要素*タグと呼ばれます。**Content**は**ContentPage**のプロパティであり、通常、単一のビューまたは子ビューを持つレイアウトに設定されます。通常、プロパティはXAMLの属性になりますが、複雑なオブジェクトに**Content**属性を設定するのは困難でしょう。そのため、プロパティは、クラス名とプロパティ名をピリオドで区切ったXML要素として表現されます。**Content**プロパティは、**ContentPage.Content**タグの間で次のように設定できます。

```xml
<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">
    <ContentPage.Content>

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

    </ContentPage.Content>
</ContentPage>
```

また、ルートタグに**Title**属性が設定されていることにも注意してください。

この時点で、クラス、プロパティ、およびXMLの関係が明白でなければなりません。Xamarin.Formsクラス（**ContentPage**や**Label**など）は、XML要素としてXAMLファイルに表示されます。**ContentPage**の**Title**と**Label**の7つのプロパティを含むそのクラスのプロパティは、通常、XML属性として表示されます。

これらのプロパティの値を設定するためのショートカットが多数存在します。たとえば、**Title**と**Text**のプロパティは**String**型、**Rotation**は**Double**型、**IsVisible**（デフォルトでは**true**で、ここではイラストレーション用にのみ設定されています）は**Boolean型**です。

**Horizo​​ntalTextAlignment**プロパティの型は**TextAlignment**で、列挙型です。任意の列挙型のプロパティに対して、必要なのはメンバ名だけです。

ただし、より複雑な型のプロパティでは、XAMLの解析にコンバーターが使用されます。これらは**TypeConverter**から派生した**Xamarin.Forms**のクラスです。多くは公開クラスですが、一部は公開クラスではありません。この特定のXAMLファイルでは、これらのクラスのいくつかがバックグラウンドで役割を果たします。

* **VerticalOptions**プロパティ用の**LayoutOptionsConverter**
* **FontSize**プロパティ用の**FontSizeConverter**
* **TextColor**プロパティ用の**ColorTypeConverter**

これらのコンバータは、プロパティ設定の許容される構文を管理します。

**ThicknessTypeConverter**は、カンマで区切られた1つ、2つ、または4つの数値を処理できます。1つの番号が指定されている場合、それは4つの側面すべてに適用されます。2つの数字の場合、最初は左と右のパディング、もう1つは上と下です。4つの数字は左、上、右、下の順になります。

**LayoutOptionsConverter**は、**LayoutOptions**構造体のpublic staticフィールドの名前を**LayoutOptions**型の値に変換できます。

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

**ColorTypeConverter**は、アルファチャンネルの有無にかかわらず、数字の記号（#）が前に付いたColor構造体または16進数のRGB値のpublic staticフィールドの名前を受け入れます。アルファチャンネルのない構文は次のとおりです。

```xml
TextColor = "＃rrggbb"
```

各小文字は16進数です。アルファチャンネルがどのように含まれているかは次のとおりです。

```xml
TextColor = "＃aarrggbb">
```

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

他の2つのフォーマットでは、各チャンネルに対して1つの16進数字のみを指定できます。

```xml
TextColor="#rgb" TextColor="#argb"
```

これらの場合、数字を繰り返して値を形成します。たとえば、＃CF3はRGBの色CC-FF-33です。

### ページナビゲーション
**XamlSamples**プログラムを実行すると、**MainPage**が表示されます。新しいHelloXamlPageを見るには、**App.xaml.cs**ファイルの新しいスタートアップページとして設定するか、MainPageから新しいページに遷移させます。

ナビゲーションを実装するには、まず**App.xaml.cs**コンストラクタのコードを変更して、**NavigationPage**オブジェクトを作成します。

```csharp
public App()
{
    InitializeComponent();
    MainPage = new NavigationPage(new MainPage());
}
```

**MainPage.xaml.cs**コンストラクタでは、シンプルな**Button**を作成し、**HelloXamlPage**に移動するためにイベントハンドラを使用することができます。

```csharp
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;
}
```

ページの**Content**プロパティを設定すると、XAMLファイルの**Content**プロパティの設定が置き換えられます。このプログラムの新しいバージョンをコンパイルしてデプロイすると、画面にボタンが表示されます。押すと、**HelloXamlPage**に遷移します。iPhone、Android、およびWindows 10 Mobileデバイスの結果ページは次のとおりです。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/HelloXaml1.png" title="Rotated Label Text" alt="Rotated Label Text" width="60%">

iOSでは **< Back** ボタンを使用してメインページに戻ることができます。Androidではページの上部にある左矢印か画面下部にある矢印を使用します。Windows 10 Mobileではページ下部にある左矢印を使用します。

ラベルをレンダリングするさまざまな方法についてXAMLを自由に試してみてください。Unicode文字をテキストに埋め込む必要がある場合は、標準のXML構文を使用できます。たとえば、挨拶をスマートクオートで囲むには、次のようにします。

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

以下はその様子です。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/HelloXaml2.png" title="Rotated Label Text with Unicode Characters" alt="Rotated Label Text with Unicode Characters" width="60%">

### XAMLとコードの相互作用
**HelloXamlPage**サンプルには、ページ上の単一のラベルのみが含まれていますが、こういう状況はあまりありません。ほとんどの**ContentPage派生クラス**は、**StackLayout**のような何らかのレイアウトに**Content**プロパティを設定します。**StackLayout**の**Children**プロパティは、**IList <View>**型に定義されていますが、実際は**ElementCollection <View>**型のオブジェクトであり、そのコレクションには複数のビューまたは他のレイアウトが設定されます。XAMLでは、これらの親子関係は通常のXML階層で確立されます。**XamlPlusCodePage**という名前の新しいページ用のXAMLファイルは次のとおりです。

```xml
<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ファイルは構文的に完成しており、次のようになります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/XamlPlusCode1.png" title="Multiple Controls on a Page" alt="Multiple Controls on a Page" width="60%">

しかし、あなたはきっとこのプログラムは機能的に不完全であると考えていることでしょう。おそらく**Slider**は**Label**に現在の値を表示させ、**Button**はおそらくプログラム内で何かを行うことを意図しています。

[パート4 データバインディングの基礎](#パート4-データバインディングの基礎)で説明するように、**Label**を使用して**Slider**値を表示するには、データバインディングを使用してXAMLで完全に処理できます。しかし、コードソリューションを最初に見ておくと便利です。それでも、ボタンクリックを処理するにはコードが必要です。つまり、**XamlPlusCodePage**のコードビハインドファイルには、**Slider**の**ValueChanged**イベントと**Button**の**Clicked**イベントのハンドラが含まれている必要があります。それらを追加しましょう。

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

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}
```

これらのイベントハンドラはpublicである必要はありません。

XAMLファイルに戻ると、**Slider**タグと**Button**タグには、これらのハンドラを参照する**ValueChanged**イベントと**Clicked**イベントの属性が含まれている必要があります。

```xml
<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>
```

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

**Slider**の**ValueChanged**イベントのハンドラが**Label**を使用して現在の値を表示する場合、ハンドラはコードからそのオブジェクトを参照する必要があります。

**Label**には**x:Name**属性で指定された名前が必要です。

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

**x:Name**属性のxプレフィックスは、この属性がXAMLに固有であることを示します。

**x:Name**属性に割り当てる名前は、C#変数名と同じ規則です。たとえば、文字またはアンダースコアで始まり、埋め込みスペースを含まないようにする必要があります。

**ValueChanged**イベントハンドラは、新しい**Slider**値を表示するよう**Label**を設定できるようになりました。新しい値はイベントの引数から取得できます。

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

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

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

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

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/Images/XamlPlusCode2.png" title="Slider Value Displayed" alt="Slider Value Displayed" width="60%">

次は**Button**です。**Clicked**イベントに対する応答を、ボタンの**Text**で警告を表示してシミュレートしましょう。イベントハンドラは、**sender**引数を**Button**に安全にキャストし、そのプロパティにアクセスできます。

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

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

XAMLで定義されたオブジェクトがコードビハインドファイルで処理されるイベントを発生させ、XAMLで定義されたオブジェクトにコードビハインドファイルが**x:Name**属性で割り当てられた名前でアクセスできることがわかりました。これらはコードとXAMLが相互作用する2つの基本的な方法です。

新しく生成された**XamlPlusCode.xaml.g.cs**ファイル（**x:Name**属性にプライベートフィールドとして割り当てられた任意の名前が含まれる）を調べることで、XAMLの動作に関する追加の洞察を得ることができます。そのファイルの簡略版は次のとおりです。

```csharp
public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

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

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

**InitializeComponent**がコントロールをコンストラクタに返すと、ページのビジュアルは、コードでインスタンス化され、初期化されたかのように構築されます。XAMLファイルはクラス内のどの役割も果たさなくなりました。たとえば、**StackLayout**にビューを追加したり、ページの**Content**プロパティを完全に別のものに設定したりするなど、任意の方法でページ上のこれらのオブジェクトを操作できます。ページの**Content**プロパティと**Children**コレクションのレイアウトの項目を調べることで、「ツリー構造をたどる」ことができます。この方法でアクセスされるビューにプロパティを設定したり、イベントハンドラを動的に割り当てることができます。

どうぞ。それはあなたのページです。XAMLはコンテンツを構築するためのツールに過ぎません。

### まとめ
ここでは、XAMLファイルとコードファイルがクラス定義にどのように寄与し、XAMLとコードファイルがどのように相互作用するかを見てきました。しかし、XAMLには独自の構文上の特徴があり、非常に柔軟に使用することができます。
[パート2 XAML構文の本質] (#パート2-xaml構文の本質)で詳しく見て行きましょう。

## [パート2 XAML構文の本質](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/essential_xaml_syntax/)

**プロパティ要素と添付プロパティの操作**

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

### プロパティ要素
XAMLでは、クラスのプロパティは通常XML属性として設定されます。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large"
       TextColor="Aqua" />
```

しかし、XAMLでプロパティを設定する別の方法があります。**TextColor**でこの代替方法を試すには、まず既存の**TextColor**設定を削除します。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large" />
```

空要素の**Label**タグを開始タグと終了タグに分けて開きます。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">

</Label>
```

次のように、これらの新しいタグの内容としてプロパティ値を設定します。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>
```

**TextColor**プロパティを指定するこれらの2つの方法は機能的には同等ですが、同じプロパティに対して2つの方法を使用しないでください。プロパティを2回設定してしまい、あいまいになってしまうためです。

この新しい構文では、いくつかの便利な用語を紹介することができます。

* **Label**は*オブジェクト要素*です。これはXML要素として表現されたXamarin.Formsオブジェクトです。
* **Text**、**VerticalOptions**、**FontAttributes**、**FontSize**は*プロパティ属性*です。
* 最後のスニペットでは、**TextColor**は*プロパティ要素*になりました。これはXamarin.Formsプロパティですが、XML要素になりました。

プロパティ要素の定義は、最初はXML構文の違反と思われるかもしれませんが、そうではありません。ピリオドはXMLでは特別な意味を持ちません。XMLデコーダにとっては、**Label.TextColor**は単なる通常の子要素です。

しかし、XAMLでは、この構文は非常に特殊です。プロパティ要素の規則の1つは、**Label.TextColor**タグに何も表示されないことです。プロパティの値は、プロパティ要素の開始タグと終了タグの間のコンテンツとして常に定義されます。

複数のプロパティでプロパティ要素構文を使用できます。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="Center">
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>
```

または、すべてのプロパティーに対してプロパティー要素構文を使用できます。

```xml
<Label>
    <Label.Text>
        Hello, XAML!
    </Label.Text>
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
    <Label.VerticalOptions>
        Center
    </Label.VerticalOptions>
</Label>
```

最初に、プロパティ要素の構文は比較的簡単なものの、不要で冗長な置き換えのように見えるかもしれません。これらの例では確かです。

しかし、プロパティの値が複雑すぎて単純な文字列として表現できない場合は、プロパティ要素の構文が不可欠になります。プロパティ要素タグ内で、別のオブジェクトをインスタンス化してプロパティを設定することができます。たとえば、**VerticalOptions**などのプロパティをプロパティ設定で**LayoutOptions**値に明示的に設定することができます。

```xml
<Label>
    ...
    <Label.VerticalOptions>
        <LayoutOptions Alignment="Center" />
    </Label.VerticalOptions>
</Label>
```

別の例: **Grid**には**RowDefinitions**と**ColumnDefinitions**という2つのプロパティがあります。これら2つのプロパティは、**RowDefinitionCollection**、**ColumnDefinitionCollection**タイプです。これらは**RowDefinition**、**ColumnDefinition**オブジェクトのコレクションです。

**RowDefinitions**コレクションと**ColumnDefinitions**コレクションのプロパティ要素タグを示す、**GridDemoPage**クラスのXAMLファイルの最初は次のとおりです。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        ...
    </Grid>
</ContentPage>
```

自動サイズのセル、ピクセルの幅と高さのセル、および星の設定を定義するための省略形の構文に注目してください。

### 添付プロパティ
**Grid**は、行と列を定義するために**RowDefinitions**コレクションと**ColumnDefinitions**コレクションのプロパティ要素が必要であることがわかりました。しかし、プログラマが**Grid**の子が置かれている行と列を指示する方法もなければなりません。

**Grid**の子のタグ内で、次の属性を使用してその子の行と列を指定します。

* **Grid.RowSpan**
* **Grid.ColumnSpan**

これら2つの属性のデフォルト値は1です。

完成したGridDemoPage.xamlファイルがこちらです。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>

        <Label Text="Autosized cell"
               Grid.Row="0" Grid.Column="0"
               TextColor="White"
               BackgroundColor="Blue" />

        <BoxView Color="Silver"
                 HeightRequest="0"
                 Grid.Row="0" Grid.Column="1" />

        <BoxView Color="Teal"
                 Grid.Row="1" Grid.Column="0" />

        <Label Text="Leftover space"
               Grid.Row="1" Grid.Column="1"
               TextColor="Purple"
               BackgroundColor="Aqua"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Span two rows (or more if you want)"
               Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
               TextColor="Yellow"
               BackgroundColor="Blue"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Span two columns"
               Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
               TextColor="Blue"
               BackgroundColor="Yellow"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Fixed 100x100"
               Grid.Row="2" Grid.Column="2"
               TextColor="Aqua"
               BackgroundColor="Red"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

    </Grid>
</ContentPage>
```

**Grid.Row**と**Grid.Column**の0の設定は必須ではありませんが、一般的には分かりやすくするために含まれています。

3つのプラットフォームすべてでこのように見えます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/essential_xaml_syntax/Images/GridDemo.png" title="Grid Layout" alt="Grid Layout" width="60%">

これらの**Grid.Row**、**Grid.Column**、**Grid.RowSpan**、**Grid.ColumnSpan**の各属性は、構文から判断すると、静的なフィールドか**Grid**のプロパティであるように見えますが、興味深いことに、**Grid**では**Row**、**Column**、**RowSpan**、**ColumnSpan**という名前は定義されていません。

その代わり、**Grid**では**RowProperty**、**ColumnProperty**、**RowSpanProperty**、**ColumnSpanProperty**という4つのバインド可能なプロパティが定義されています。これらは、*添付プロパティ*として知られている特別なタイプのバインド可能なプロパティです。それらは**Grid**クラスによって定義されますが、**Grid**の子に設定されます。

これらの添付プロパティをコードで使用する場合、**Grid**クラスは**SetRow**、**GetColumn**などの静的メソッドを提供します。しかし、XAMLでは、これらの添付プロパティは、単純なプロパティ名を使用して**Grid**の子に属性として設定されます。

添付プロパティは、XAMLファイルでは、クラスとプロパティ名をピリオドで区切った属性として認識することができます。あるクラス（この例では**Grid**）で定義されているが、他のオブジェクト（この場合は**Grid**の子）に添付されているため、*添付プロパティ*と呼ばれます。レイアウト中、**Grid**はこれらの添付プロパティの値を調べて、各子をどこに配置するかを知ることができます。

**AbsoluteLayout**クラスは、**LayoutBounds**と**LayoutFlags**という2つの添付プロパティを定義します。**AbsoluteLayout**の比率を維持した配置とサイジングの機能を使って実現したチェッカーボードパターンです

```xml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.AbsoluteDemoPage"
             Title="Absolute Demo Page">

    <AbsoluteLayout BackgroundColor="#FF8080">
        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

  </AbsoluteLayout>
</ContentPage>
```

このように表示されます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/essential_xaml_syntax/Images/AbsoluteDemo-large.png" title="Absolute Layout" alt="Absolute Layout" width="60%">

このような実装をするにあたっては、XAMLでの実装は賢明でないと感じるかもしれません。確かに、**LayoutBounds**矩形の繰り返しと規則性は、コードでよりよく実現できることを示唆しています。

これは確かに正当な懸案事項であり、ユーザインターフェースの定義時にコードとマークアップの使用のバランスをとることには問題ありません。XAMLでビジュアルの一部を定義してから、コードビハインドファイルのコンストラクタを使用して、ループでより効率的に生成されるビジュアルを追加できます。

### コンテントプロパティ
前の例では、**StackLayout**、**Grid**、**AbsoluteLayout**オブジェクトは**ContentPageのContent**プロパティに設定され、これらのレイアウトの子は実際には**Children**コレクション内の項目です。しかし、これらの**Content**および**Children**プロパティはXAMLファイルにはありません。

**XamlPlusCode**サンプルのように、**Content**要素と**Children**プロパティを明示的にプロパティ要素として含めることができます。

```xml
<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">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout.Children>
                <Slider VerticalOptions="CenterAndExpand"
                        ValueChanged="OnSliderValueChanged" />

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

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

XAMLファイルでこれらのプロパティ要素が*不要*なのはなぜでしょうか？

XAMLで使用するためにXamarin.Formsで定義された要素は、そのクラスの**ContentProperty**属性にフラグが立てられた1つのプロパティを持つことができます。オンラインのXamarin.Formsドキュメントで**ContentPage**クラスを調べると、次の属性が見つかります。

```csharp
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
```

これは**Content**プロパティ要素タグは必須ではないという意味です。**ContentPage**タグの先頭と末尾の間に表示されるXMLコンテンツは、**Content**プロパティに割り当てられているものとみなされます。

**StackLayout**、**Grid**、**AbsoluteLayout**、**RelativeLayout**はすべて**Layout <View>**から派生し、Xamarin.Formsドキュメントで**Layout <T>**を調べると、別の**ContentProperty**属性が見つかります。

```csharp
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
```

これにより、レイアウトのコンテンツを明示的な**Children**プロパティ要素タグなしで**Children**コレクションに自動的に追加することができます。

他のクラスにも**ContentProperty**属性定義があります。たとえば、**Label**の**Content**プロパティは**Text**です。他のAPIドキュメントをチェックしてみてください。

### OnPlatformとプラットフォームの違い
シングルページアプリケーションでは、iOSのステータスバーを上書きしないように、ページの**Padding**プロパティを設定するのが一般的です。コードでは、この目的で**Device.RuntimePlatform**プロパティを使用できます。

```csharp
if (Device.RuntimePlatform == Device.iOS)
{
    Padding = new Thickness(0, 20, 0, 0);
}
```

また、**OnPlatform**クラスと**On**クラスを使用して、XAMLでも同様のことを行うことができます。まず、ページの上部にある**Padding**プロパティのプロパティ要素を含めます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>

    </ContentPage.Padding>
    ...
</ContentPage>
```

これらのタグには、**OnPlatform**タグが含まれています。**OnPlatform**はジェネリッククラスです。ジェネリック型の引数を指定する必要があります。この場合は、**Padding**プロパティの型である**Thickness**を指定します。幸い、**x:TypeArguments**というジェネリック引数を定義するためのXAML属性があります。これは設定しているプロパティの型と一致する必要があります。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">

        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```
**OnPlatform**には、**On**オブジェクトの**IList**である**Platforms**という名前のプロパティがあります。そのプロパティのプロパティ要素タグを使用します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <OnPlatform.Platforms>

            </OnPlatform.Platforms>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

**On**要素を追加します。各要素には、**Platform**プロパティと、**Thickness**プロパティのマークアップ用の**Value**プロパティを設定します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <OnPlatform.Platforms>
                <On Platform="iOS" Value="0, 20, 0, 0" />
                <On Platform="Android" Value="0, 0, 0, 0" />
                <On Platform="UWP" Value="0, 0, 0, 0" />
            </OnPlatform.Platforms>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

このマークアップは単純化することができます。 **OnPlatform**の**Content**プロパティは**Platforms**であるため、これらのプロパティ要素タグは削除できます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
            <On Platform="Android" Value="0, 0, 0, 0" />
            <On Platform="UWP" Value="0, 0, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

**On**の**Platform**プロパティは**IList <string>**型であるため、値が同じ場合は複数のプラットフォームを含めることができます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
            <On Platform="Android, UWP" Value="0, 0, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

AndroidとWindowsは**Padding**のデフォルト値に設定されているので、そのタグは削除できます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

これは、XAMLでプラットフォーム依存の**Padding**プロパティを設定する標準的な方法です。**Value**の設定を単一の文字列で表すことができない場合は、プロパティの要素を定義できます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS">
                <On.Value>
                    0, 20, 0, 0
                </On.Value>
            </On>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>
```

### まとめ
プロパティ要素と添付プロパティに関して基本的なXAML構文の多くが確立されています。しかし、リソースディクショナリーなどの間接的な方法でオブジェクトにプロパティを設定する必要がある場合もあります。このアプローチは、次の部で説明されています。


## [パート3 XAMLマークアップ拡張](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/xaml_markup_extensions/)

**一般化されたオブジェクト参照構文の探索**

XAMLマークアップ拡張は、他のソースから間接的に参照されるオブジェクトまたは値にプロパティを設定できるXAMLの重要な機能です。XAMLマークアップ拡張は、オブジェクトの共有やアプリケーション全体で使用される定数の参照に特に重要ですが、データバインディングで最大の有用性を見出します。

### XAMKマークアップ拡張
一般に、XAMLを使用してオブジェクトのプロパティを文字列、数値、列挙型メンバ、または裏で値に変換された文字列などの明示的な値に設定します。

ただし、プロパティは他の場所で定義された値を参照するか、実行時にコードによって少し処理する必要がある場合があります。これらの目的のために、XAMLマークアップ拡張が利用できます。

これらのXAMLマークアップ拡張は、XMLの拡張ではありません。 XAMLは正式なXMLです。それらは**IMarkupExtension**を実装しているクラスのコードに裏付けられているので、「拡張」と呼ばれています。独自のカスタムマークアップ拡張を書くことができます。

多くの場合、XAMLマークアップ拡張は中括弧（{と}）で区切られた属性設定として表示されるため、XAMLファイルで即座に認識されますが、マークアップ拡張が従来の要素としてマークアップに表示されることがあります。

### 共有リソース
一部のXAMLページには、プロパティが同じ値に設定された複数のビューが含まれています。たとえば、これらの**Button**オブジェクトの多くのプロパティ設定は同じです。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="Large" />

        <Button Text="Do that!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="Large" />

        <Button Text="Do the other thing!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="Large" />

    </StackLayout>
</ContentPage>
```

これらのプロパティのいずれかを変更する必要がある場合は、変更を3回ではなく1回だけ行うことをお勧めします。これがコードの場合は、定数や静的な読み取り専用オブジェクトを使用して、そのような値の一貫性を保ち、変更しやすくすることでしょう。

XAMLでは、そのような値やオブジェクトを*リソースディクショナリー*に格納することが一般的な解決策の1つです。**VisualElement**クラスは**ResourceDictionary**型の**Resources**という名前のプロパティを定義します。これは、**string**型のキーと**object**型の値を持つ辞書です。この辞書にオブジェクトを配置し、XAML内のすべてのオブジェクトをマークアップから参照できます。

ページ上でリソースディクショナリーを使用するには、リソースのプロパティ要素タグのペアを含めます。これらをページの一番上に置くのが最も便利です。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>

    </ContentPage.Resources>
    ...
</ContentPage>
```

明示的に**ResourceDictionary**タグを含める必要もあります。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>

        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>
```

様々なタイプのオブジェクトと値をリソースディクショナリーに追加できるようになりました。これらの型はインスタンス化可能でなければなりません。たとえば、抽象クラスにすることはできません。これらの型には、パブリックなパラメータのないコンストラクタも必要です。各項目には、**x:Key**属性で指定された辞書キーが必要です。例えば次のようになります。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>
```

これらの2つの項目は**LayoutOptions**構造体型の値であり、それぞれ固有のキーと1つか2つのプロパティーセットを持ちます。コードやマークアップでは、**LayoutOptions**の静的フィールドを使用する方がはるかに一般的ですが、今回はプロパティを設定する方が便利です。

これらのボタンの**Horizo​​ntalOptions**プロパティと**VerticalOptions**プロパティをこれらのリソースに設定する必要があります。これは**StaticResource** XAMLマークアップ拡張で行います

```xml
<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="3"
        Rotation="-15"
        TextColor="Red"
        FontSize="Large" />
```

**StaticResource**マークアップ拡張子は、常に中括弧で区切られ、辞書キーが含まれています。

**StaticResource**という名前は、Xamarin.Formsでもサポートされている**DynamicResource**と区別されます。**DynamicResource**は実行時に変更される可能性のある値に関連付けられた辞書キー用であるのに対し、**StaticResource**はページ上の要素が構築されたときに、一度だけ辞書から要素にアクセスします。

**BorderWidth**プロパティの場合は、辞書にdouble型の値を格納する必要があります。XAMLは**x:Double**や**x:Int32**のような一般的なデータ型のタグを便利に定義します。

```xml
<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

        <x:Double x:Key="borderWidth">
            3
        </x:Double>
    </ResourceDictionary>
</ContentPage.Resources>
```

それを3行にする必要はありません。この回転角度の辞書エントリーは1行だけです。

```xml
<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

         <x:Double x:Key="borderWidth">
            3
         </x:Double>

        <x:Double x:Key="rotationAngle">-15</x:Double>
    </ResourceDictionary>
</ContentPage.Resources>
```

これらの2つのリソースは、**LayoutOptions**の値と同じ方法で参照できます。

```xml
<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="Red"
        FontSize="Large" />
```

**Color**型のリソースの場合、これらの型の属性を直接割り当てるときに使用するものと同じ文字列表現を使用できます。型コンバーターは、リソースが作成されるときに呼び出されます。ここに**Color**というタイプのリソースがあります。

```xml
<Color x:Key="textColor">Red</Color>
```

**FontSize**プロパティには少し問題があります。このプロパティは**double**型であると定義されています。プロパティを**Large**などの**NamedSize**列挙体のメンバに設定すると、**FontSizeConverter**クラスは背後で動作し、**Device.GetNamedSized**メソッドを使用してプラットフォーム依存の値に変換します。

しかし、フォントサイズのリソースを**double**として定義して値を "Large"に設定することはできません。XAMLパーサーがリソースを処理するときに、値がフォントサイズとして使用されることはわかりません。

解決策は、**x:String**型を使用してリソースを文字列として定義することです。

```xml
<x:String x:Key="fontSize">Large</x:String>
```

**Text**以外のすべてのプロパティは、リソース設定で定義されます。

```xml
<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="{StaticResource textColor}"
        FontSize="{StaticResource fontSize}" />
```

リソースディクショナリー内で**OnPlatform**を使用して、プラットフォームに異なる値を定義することもできます。**OnPlatform**オブジェクトをさまざまなテキストカラーのリソースディクショナリーに含める方法は次のとおりです。

```xml
<OnPlatform x:Key="textColor"
            x:TypeArguments="Color">
    <On Platform="iOS" Value="Red" />
    <On Platform="Android" Value="Aqua" />
    <On Platform="UWP" Value="#80FF80" />
</OnPlatform>
```

**OnPlatform**は辞書内のオブジェクトであるため**x:Key**属性を取得し、ジェネリッククラスであるため**x:TypeArguments**属性を取得することに注意してください。オブジェクトが初期化されると、**iOS**、**Android**、**UWP**属性は**Color**値に変換されます。

6つの共有値にアクセスする3つのボタンを備えた、完成した状態のXAMLファイルは次のようになります。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />

            <x:Double x:Key="borderWidth">3</x:Double>

            <x:Double x:Key="rotationAngle">-15</x:Double>

            <OnPlatform x:Key="textColor"
                        x:TypeArguments="Color"
                <On Platform="iOS" Value="Red" />
                <On Platform="Android" Value="Aqua" />
                <On Platform="UWP" Value="#80FF80" />
            </OnPlatform>

            <x:String x:Key="fontSize">Large</x:String>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize"{StaticResource fontSize}" />

        <Button Text="Do that!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

        <Button Text="Do the other thing!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

    </StackLayout>
</ContentPage>
```

スクリーンショットで一貫したスタイリングとプラットフォームに依存するスタイリングを見てみましょう。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/xaml_markup_extensions/Images/SharedResources.png" title="Styled Controls" alt="Styled Controls" width="60%">

ページ上部で**Resources**コレクションを定義するのが最も一般的ですが、**Resources**プロパティは**VisualElement**によって定義され、ページ上の他の要素には**Resource**sコレクションを持つことができるということを覚えておいてください。例えば、この例では**StackLayout**に追加してみましょう。

```xml
<StackLayout>
    <StackLayout.Resources>
        <ResourceDictionary>
            <Color x:Key="textColor">Blue</Color>
        </ResourceDictionary>
    </StackLayout.Resources>
    ...
</StackLayout>
```

ボタンのテキストの色が青色になっていることがわかります。基本的には、XAMLパーサが**StaticResource**マークアップ拡張を検出するたびに、ビジュアルツリーを検索し、そのキーを含む最初の**ResourceDictionary**を使用します。

リソース辞書に格納されている最も一般的なオブジェクトの1つは、プロパティ設定のコレクションを定義するXamarin.Formsの**Style**です。スタイルについては、 [Style](https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/)の記事で説明します。

XAMLを初めて使用する開発者は、**Label**や**Button**などのビジュアル要素を**ResourceDictionary**に配置できるかどうか疑問に思うことがあります。確かに可能ですが、あまり意味がありません。**ResourceDictionary**の目的は、オブジェクトを共有することです。ビジュアル要素は共有できません。同じインスタンスを1ページに2回表示することはできません。

### x:Staticマークアップ拡張
名前は似ていますが、**x:Static**と**StaticResource**はかなり異なっています。**StaticResource**はリソースディクショナリーからオブジェクトを返します一方で**x:Static**は次のいずれかにアクセスします。

* public staticフィールド
* public staticプロパティ
* public constフィールド
* 列挙メンバー

**StaticResource**マークアップ拡張はリソースディクショナリーを定義するXAML実装でサポートされ、**x:Static**は**x**プレフィックスからわかるようにXAMLの本質的な部分です。

**x:static**が静的フィールドと列挙メンバーを明示的に参照できる方法を示すいくつかの例を示します。

```xml
<Label Text="Hello, XAML!"
       VerticalOptions="{x:Static LayoutOptions.Start}"
       HorizontalTextAlignment="{x:Static TextAlignment.Center}"
       TextColor="{x:Static Color.Aqua}" />
```

これまでのところ、これはあまり印象的ではありません。しかし、**x:Static**マークアップ拡張は、自分のコードから静的フィールドやプロパティを参照することもできます。たとえば、**AppConstants**クラスには、アプリケーション全体で複数のページで使用する静的フィールドがいくつか含まれているとします。

```csharp

using System;
using Xamarin.Forms;

namespace XamlSamples
{
    static class AppConstants
    {
        public static readonly Thickness PagePadding;

        public static readonly Font TitleFont;

        public static readonly Color BackgroundColor = Color.Aqua;

        public static readonly Color ForegroundColor = Color.Brown;

        static AppConstants()
        {
            switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    PagePadding = new Thickness(5, 20, 5, 0);
                    TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
                    break;

                case Device.Android:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
                    break;

                case Device.UWP:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
                    break;
            }
        }
    }
}
```

XAMLファイルでこのクラスの静的フィールドを参照するには、XAMLファイル内でこのファイルの場所を示す方法が必要です。これは、XML名前空間宣言で行います。

標準のXamarin.Forms XAMLテンプレートの一部として作成されたXAMLファイルには、Xamarin.FormsクラスにアクセスするためのXML名前空間宣言と、XAMLに固有のタグと属性を参照するためのXML名前空間宣言の2つのXML名前空間宣言が含まれています。

```xml
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
```

他のクラスにアクセスするには、追加のXML名前空間宣言が必要です。追加の各XML名前空間宣言は、新しいプレフィックスを定義します。**AppConstants**など、共有アプリケーションPCLのローカルクラスにアクセスするには、XAMLプログラマはよくlocalプレフィックスを使用します。名前空間宣言は、CLR（共通言語ランタイム）名前空間名（.NET名前空間名とも呼ばれます）を示す必要があります。これは、C＃**名前空間**定義または**using**ディレクティブに表示される名前です。

```xml
xmlns:local="clr-namespace:XamlSamples"
```

また、PCLが参照するアセンブリ内の.NET名前空間のXML名前空間宣言を定義することもできます。たとえば、かつて**mscorlib**アセンブリにおいて「Microsoft Common Object Runtime Library」を意味したの標準.NET System名前空間の**sys**プレフィックスが今では「多言語標準共通オブジェクトランタイムライブラリ」を意味します。これは別のアセンブリなので、アセンブリ名（この場合は**mscorlib**）も指定する必要があります。

```xml
xmlns:sys="clr-namespace:System;assembly=mscorlib"
```

キーワード**clr-namespace**の後にはコロン、次に.NET名前空間の名前、セミコロン、キーワード**アセンブリ**、等号、アセンブリ名が続きます。

そうです、コロンは**clr-namespace**の後に続きますが、等号は**アセンブリ**の後に続きます。構文はこのようにして意図的に定義されました。大部分のXML名前空間宣言は、**http**などのURIスキーム名を開始するURIを参照し、その後には常にコロンが続きます。この文字列の**clr-namespace**部分は、その慣習を模倣するためのものです。

これらの名前空間宣言は、両方とも**StaticConstantsPage**サンプルに含まれています。BoxViewの次元はMath.PIとMath.Eに設定されていますが、100倍にスケーリングされています。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             x:Class="XamlSamples.StaticConstantsPage"
             Title="Static Constants Page"
             Padding="{x:Static local:AppConstants.PagePadding}">

    <StackLayout>
       <Label Text="Hello, XAML!"
              TextColor="{x:Static local:AppConstants.BackgroundColor}"
              BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
              Font="{x:Static local:AppConstants.TitleFont}"
              HorizontalOptions="Center" />

      <BoxView WidthRequest="{x:Static sys:Math.PI}"
               HeightRequest="{x:Static sys:Math.E}"
               Color="{x:Static local:AppConstants.ForegroundColor}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand"
               Scale="100" />
    </StackLayout>
</ContentPage>
```

結果として得られるBoxViewの画面に対するサイズは、プラットフォームによって異なります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/xaml_markup_extensions/Images/StaticConstants.png" title="Controls using x:Static Markup Extension" alt="Controls using x:Static Markup Extension" width="60%">

### その他の標準マークアップ拡張
いくつかのマークアップ拡張はXAMLに固有であり、Xamarin.Forms XAMLファイルでサポートされています。これらのうちのいくつかは頻繁には使用されませんが、必要なときには不可欠です。

* デフォルトでプロパティが**null**以外の値を持っているが、**null**に設定する場合は、**{x:Null}**マークアップ拡張に設定します。
* プロパティが**Type**型の場合は、マークアップ拡張子**{x:Type someClass}**を使用して**Tyep**オブジェクトに割り当てることができます。
* **x:Array**マークアップ拡張を使用してXAMLで配列を定義できます。このマークアップ拡張には、配列内の要素の型を示す**Type**という必須属性があります。
* **Binding**マークアップ拡張については、[パート4 データバインディングの基礎](#パート4-データバインディングの基礎)で説明します。

### ConstraintExpressionマークアップ拡張
マークアップ拡張はプロパティを持つことができますが、XML属性のようには設定されません。マークアップ拡張では、プロパティ設定がコンマで区切られ、中括弧内に引用符は表示されません。

これは、RelativeLayoutクラスで使用される**ConstraintExpression**という名前のXamarin.Formsマークアップ拡張で説明できます。子ビューの位置またはサイズを定数として指定することも、親ビューや他の名前付きビューを基準に指定することもできます。ConstraintExpressionの構文を使用すると、別のビューのプロパティを倍にする**Factor**と**Constant**を加えたものを使用して、ビューの位置またはサイズを設定できます。それより複雑なものはコードが必要です。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.RelativeLayoutPage"
             Title="RelativeLayout Page">

    <RelativeLayout>

        <!-- Upper left -->
        <BoxView Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Upper right -->
        <BoxView Color="Green"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Lower left -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />
        <!-- Lower right -->
        <BoxView Color="Yellow"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />

        <!-- Centered and 1/3 width and height of parent -->
        <BoxView x:Name="oneThird"
                 Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"  />

        <!-- 1/3 width and height of previous -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=X}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Y}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Height,
                                            Factor=0.33}"  />
    </RelativeLayout>
</ContentPage>
```

おそらくこのサンプルから取るべき最も重要な教訓は、マークアップ拡張の構文です。マークアップ拡張の中括弧内に引用符は使用できません。XAMLファイルにマークアップ拡張を入力するときは、プロパティの値を引用符で囲みます。誘惑に負けないでください！

実行すると次のようになります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/xaml_markup_extensions/Images/RelativeLayout.png" title="Relative Layout using Constraints" alt="Relative Layout using Constraints" width="60%">

### まとめ
ここに示すXAMLマークアップ拡張は、XAMLファイルの重要なサポートを提供します。しかしおそらく最も価値のあるXAMLマークアップの拡張はBindingです。これについては、このシリーズの次のパートで説明します。

## [パート4 データバインディングの基礎](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/)
**XAMLファイルのプロパティのリンク**

データバインディングを使用すると、2つのオブジェクトのプロパティがリンクされ、一方を変更すると他方が変更されます。これは非常に価値あるツールです。データバインディングをコードで完全に定義できますが、XAMLはショートカットと利便性を提供します。したがって、Xamarin.Formsの最も重要なマークアップ拡張の1つはBindingです。

### データバインディング
データバインディングは、*ソース*と*ターゲット*と呼ばれる2つのオブジェクトのプロパティを接続します。コードでは、2つのステップが必要です。ターゲットオブジェクトのBindingContextプロパティは、ソースオブジェクトに設定する必要があります。ターゲットオブジェクトのプロパティをソースオブジェクトのプロパティにバインドするには、ターゲットオブジェクトに対して**SetBinding**メソッド（**Binding**クラスと組み合わせて使用​​されることが多い）を呼び出す必要があります。

ターゲットプロパティはバインダブルプロパティでなければなりません。つまり、ターゲットオブジェクトは**BindableObject**から派生する必要があります。オンラインのXamarin.Formsドキュメントでは、どのプロパティがバインダブルプロパティであるかを説明しています。TextなどのLabelのプロパティは、バインダブルプロパティ**TextProperty**に関連付けられています。

マークアップでは、コードに必要な同じ2つの手順も実行する必要があります。ただし、**Binding**マークアップ拡張が**SetBinding**呼び出しと**Binding**クラスの代わりに使用される点が異なります。

しかし、XAMLでデータバインディングを定義する場合、ターゲットオブジェクトの**BindingContext**を設定する方法は複数あります。場合によっては、**StaticResource**または**x:Static**マークアップ拡張を使用するコードビハインドファイルから設定されることもあります。また、**BindingContext**のプロパティ要素タグの内容として設定されることもあります。

バインディングは、プログラムのビジュアルを基になるデータモデルと結びつけるために最も頻繁に使用されます。特に、[パート5 データバインディングからMVVMへ](#パート5-データバインディングからmvvmへ)で議論するように、MVVM（Model-View-ViewModel）アプリケーション・アーキテクチャーを実現する際に通常は使用されますが、他のシナリオでも使用できます。

### ビューからビューへのバインディング
同じページ上の2つのビューのプロパティをリンクするデータバインディングを定義できます。この場合、**x:Reference**マークアップ拡張を使用してターゲットオブジェクトの**BindingContext**を設定します。

次の例では、**Slide**rと2つの**Label**ビューが含まれているXAMLファイルがあり、そのうちの1つは**Slider**値で回転し、もう1つは**Slider**値を表示します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderBindingsPage"
             Title="Slider Bindings Page">

    <StackLayout>
        <Label Text="ROTATION"
               BindingContext="{x:Reference Name=slider}"
               Rotation="{Binding Path=Value}"
               FontAttributes="Bold"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="CenterAndExpand" />

        <Label BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
               FontAttributes="Bold"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>
```

**Slider**には、**x:Reference**マークアップ拡張を使用して2つの**Label**ビューによって参照される**x:Name**属性が含まれています。

**x:Reference**バインディング拡張では、**Name**という名前のプロパティを定義して、参照される要素（この場合は**slider**）の名前を設定します。しかし、**x:Reference**マークアップ拡張を定義する**ReferenceExtension**クラスでは、明示的に必須ではないことを意味する**Name**の**ContentProperty**属性も定義されています。最初の**x:Reference**には "Name ="が含まれていますが、2番目にはありません。

```csharp
BindingContext="{x:Reference Name=slider}"
…
BindingContext="{x:Reference slider}"
```

**Binding**マークアップ拡張機能自体には、**BindingBase**クラスや**Binding**クラスと同様に、いくつかのプロパティがあります。**Binding**の**ContentProperty**は**Path**ですが、パスがBindingマークアップ拡張の最初の項目である場合は、マークアップ拡張の "Path ="部分を省略できます。最初の例には "Path ="がありますが、2番目の例では省略しています。

```csharp
Rotation="{Binding Path=Value}"
…
Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
```

プロパティは、すべて1行にすることも、複数行に分割することもできます。

```csharp
Text="{Binding Value, 
               StringFormat='The angle is {0:F0} degrees'}"
```

都合のいいように書いてください。

2番目の**Binding**マークアップ拡張の**StringFormat**プロパティに注目してください。Xamarin.Formsでは、バインディングは暗黙の型変換を実行しません。文字列以外のオブジェクトを文字列として表示する必要がある場合は、型変換を提供するか、**StringFormat**を使用する必要があります。背後では、静的な**String.Format**メソッドを使用して**StringFormat**を実装します。これは潜在的に問題です。.NETの書式指定には中括弧が含まれていますが、これはマークアップ拡張の区切りにも使用されるためです。これにより、XAMLパーサーを混乱させる危険があります。回避するには、書式設定文字列全体をシングルクオートで囲みます。

```csharp
Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
```

実行中のプログラムは次のとおりです。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/Images/SliderBinding.png" title="View-to-View Bindings" alt="View-to-View Bindings" width="60%">

### バインディングモード
1つビューは、複数のプロパティにデータバインディングを設定することができます。しかし、各ビューには**BindingContext**が1つしかないため、そのビューの複数のデータバインディングはすべて同じオブジェクトのすべてのプロパティを参照する必要があります。

この問題やその他の問題を解決するために、**BindingMode**列挙体のメンバに設定されている**Mode**プロパティがあります。

* **Default**
* **OneWay** — 値はソースからターゲットに転送されます
* **OneWayToSource** — 値はターゲットからソースに転送されます
* **TwoWay** — 値はソースとターゲットの間で双方向に転送されます

次のプログラムは、**OneWayToSource**および**TwoWay**バインディングモードの一般的な使用方法の1つを示しています。4つの**Slider**ビューは、ラベルの**Scale**、**Rotate**、**RotateX**、**RotateY**プロパティを制御するためのものです。最初は、**Label**のこれら4つのプロパティがデータバインディングターゲットである必要があるように見えます。これは、それぞれが**Slider**によって設定されているためです。しかし、**Label**の**BindingContext**は1つのオブジェクトにすぎず、4つの異なるスライダがあります。

そのため、すべてのバインディングは一見逆方向に設定されています。4つのスライダーのそれぞれの**BindingContext**は**Label**に設定され、バインディングはスライダーの**Value**プロパティに設定されます。**OneWayToSource**モードと**TwoWay**モードを使用することで、これらの**Value**プロパティで、**Label**の**Scale**、**Rotate**、**RotateX**、**RotateY**プロパティであるソースプロパティを設定できます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderTransformsPage"
             Padding="5"
             Title="Slider Transforms Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <!-- Scaled and rotated Label -->
        <Label x:Name="label"
               Text="TEXT"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <!-- Slider and identifying Label for Scale -->
        <Slider x:Name="scaleSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="1" Grid.Column="0"
                Maximum="10"
                Value="{Binding Scale, Mode=TwoWay}" />

        <Label BindingContext="{x:Reference scaleSlider}"
               Text="{Binding Value, StringFormat='Scale = {0:F1}'}"
               Grid.Row="1" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for Rotation -->
        <Slider x:Name="rotationSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="2" Grid.Column="0"
                Maximum="360"
                Value="{Binding Rotation, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationSlider}"
               Text="{Binding Value, StringFormat='Rotation = {0:F0}'}"
               Grid.Row="2" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationX -->
        <Slider x:Name="rotationXSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="3" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationX, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationXSlider}"
               Text="{Binding Value, StringFormat='RotationX = {0:F0}'}"
               Grid.Row="3" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationY -->
        <Slider x:Name="rotationYSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="4" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationY, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationYSlider}"
               Text="{Binding Value, StringFormat='RotationY = {0:F0}'}"
               Grid.Row="4" Grid.Column="1"
               VerticalTextAlignment="Center" />
    </Grid>
</ContentPage>

```

3つの**Slider**ビューのバインディングは**OneWayToSource**です。つまり、**Slider**の値によって、そのBindingContextのプロパティが変更されます。それは**label**という名前の**Label**です。これら3つの**Slider**ビューは、**Label**の**Rotate**、**RotateX**、**RotateY**プロパティを変更します。

しかし、**Scale**プロパティのバインディングは**TwoWay**です。これは、**Scale**プロパティのデフォルト値が1で、**TwoWay**バインディングを使用すると**Slider**の初期値が0ではなく1に設定されるためです。そのバインディングがもし**OneWayToSource**の場合、**Scale**プロパティは**Slider**のデフォルト値から最初は0に設定されます。ラベルは表示されず、ユーザーに混乱を招く可能性があります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/Images/SliderTransforms.png" title="Backwards Bindings" alt="Backwards Bindings" width="60%">

### バインディングとコレクション
テンプレート化されたListViewよりもXAMLとデータバインディングの機能が優れていることはまだ何も示されていません。

**ListView**は**IEnumerable**型の**ItemsSource**プロパティを定義し、そのコレクション内のアイテムを表示します。これらのアイテムは、どのタイプのオブジェクトでもかまいません。デフォルトでは、**ListView**は各項目の**ToString**メソッドを使用してその項目を表示します。場合によってはこれが必要な場合もありますが、多くの場合、**ToString**はオブジェクトの完全修飾クラス名のみを返します。

しかし、**ListView**コレクションのアイテムは、**Cell**から派生したクラスを含む*template*を使用して任意の方法で表示できます。テンプレートはListViewのすべてのアイテムに対して複製され、テンプレートに設定されているデータバインディングは個々の複製に転送されます。

非常に多くの場合、**ViewCell**クラスを使用してこれらの項目のカスタムセルを作成する必要があります。このプロセスはコードで行うとやや乱雑になりますが、XAMLでは非常に簡単に実現できます。

**XamlSamples**プロジェクトには**NamedColor**というクラスが含まれています。各**NamedColor**オブジェクトは、文字列型の**Name**プロパティと**FriendlyName**プロパティ、および**Color**型の**Color**プロパティを持ちます。さらに、**NamedColor**には、Xamarin.Formsの**Color**クラスで定義された色に対応する、**Color**型の静的読み取り専用フィールドが141あります。静的コンストラクタは、これらの静的フィールドに対応する**NamedColor**オブジェクトを含む**IEnumerable<NamedColor>**コレクションを作成し、そのpublic static **All**プロパティに割り当てます。

静的な**NamedColor.All**プロパティを**ListView**の**ItemsSource**に設定するには、**x:Static**マークアップ拡張を使用するのが簡単です。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">

    <ListView ItemsSource="{x:Static local:NamedColor.All}" />

</ContentPage>
```

結果を表示すると、各項目が本当に**XamlSamples.NamedColor**型であることを確認できます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/Images/ListView1.png" title="Binding to a Collection" alt="Binding to a Collection" width="60%">

情報は多くありませんが、**ListView**はスクロール可能で選択可能です。

アイテムのテンプレートを定義するには、**ItemTemplate**プロパティをプロパティ要素として分割し、**DataTemplate**に設定してから、**ViewCell**を参照する必要があります。**ViewCell**の**View**プロパティには、各アイテムを表示するための1つ以上のビューのレイアウトを定義することができます。ここに簡単な例があります。

```xml
<ListView ItemsSource="{x:Static local:NamedColor.All}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ViewCell.View>
                    <Label Text="{Binding FriendlyName}" />
                </ViewCell.View>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
```

**Label**要素は、**ViewCell**の**View**プロパティに設定されています。 **View**プロパティは**ViewCell**のコンテンツプロパティであるため、**ViewCell.View**タグは不要です。このマークアップは、各**NamedColor**オブジェクトの**FriendlyName**プロパティを表示します。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/Images/ListView2.png" title="Binding to a Collection with a DataTemplate" alt="Binding to a Collection with a DataTemplate" width="60%">

改善されましたね。今必要なのは、詳細情報と実際の色を使ってアイテムテンプレートを飾ることだけです。このテンプレートをサポートするために、ページのリソースディクショナリーにいくつかの値とオブジェクトが定義されています。

```xml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <OnPlatform x:Key="boxSize"
                        x:TypeArguments="x:Double">
                <On Platform="iOS, Android, UWP" Value="50" />
            </OnPlatform>

            <OnPlatform x:Key="rowHeight"
                        x:TypeArguments="x:Int32">
                <On Platform="iOS, Android, UWP" Value="60" />
            </OnPlatform>

            <local:DoubleToIntConverter x:Key="intConverter" />

        </ResourceDictionary>
    </ContentPage.Resources>

    <ListView ItemsSource="{x:Static local:NamedColor.All}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Padding="5, 5, 0, 5"
                                 Orientation="Horizontal"
                                 Spacing="15">

                        <BoxView WidthRequest="{StaticResource boxSize}"
                                 HeightRequest="{StaticResource boxSize}"
                                 Color="{Binding Color}" />

                        <StackLayout Padding="5, 0, 0, 0"
                                     VerticalOptions="Center">

                            <Label Text="{Binding FriendlyName}"
                                   FontAttributes="Bold"
                                   FontSize="Medium" />

                            <StackLayout Orientation="Horizontal"
                                         Spacing="0">
                                <Label Text="{Binding Color.R,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat='R={0:X2}'}" />

                                <Label Text="{Binding Color.G,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat=', G={0:X2}'}" />

                                <Label Text="{Binding Color.B,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat=', B={0:X2}'}" />
                            </StackLayout>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>
```

**OnPlatform**を使用して**BoxView**のサイズと**ListView**行の高さを定義することに注目してください。3つのプラットフォームの値はすべて同じですが、マークアップを他の値に合わせてディスプレイを微調整することも簡単にできます。

### バインディング値のコンバーター
さきほどの**ListView Demo** XAMLファイルには、Xamarin.Forms **Color**構造体の個々の**R**、**G**、**B**プロパティが表示されます。これらのプロパティは**double**型で、範囲は0〜1です。16進数の値を表示する場合は、 "X2"書式指定で**StringFormat**を使用するだけではできません。それは整数値だけで動作しますが、**double**値には255を掛ける必要があります。

この小さな問題は、*バインディングコンバーター*とも呼ばれる*バリューコンバーター*で解決されました。これは、**IValueConverter**インターフェースを実装するクラスのため、**Convert**と**ConvertBack**という2つのメソッドがあります。**Convert**メソッドは、値がソースからターゲットに転送されるときに呼び出されます。**ConvertBack**メソッドは、**OneWayToSource**または**TwoWay**バインディングでターゲットからソースへの転送に呼び出されます。

```csharp
using System;
using System.Globalization;
using Xamarin.Forms;

namespace XamlSamples
{
    class DoubleToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
                              object parameter, CultureInfo culture)
        {
            double multiplier;

            if (!Double.TryParse(parameter as string, out multiplier))
                multiplier = 1;

            return (int)Math.Round(multiplier * (double)value);
        }

        public object ConvertBack(object value, Type targetType,
                                  object parameter, CultureInfo culture)
        {
            double divider;

            if (!Double.TryParse(parameter as string, out divider))
                divider = 1;

            return ((double)(int)value) / divider;
        }
    }
}
```

バインディングはソースからターゲットへの一方向のため、**ConvertBack**メソッドはこのプログラムでは役割を果たしません。

バインディングはバインディングコンバーターを**Converter**プロパティで参照します。バインディングコンバーターは、**ConverterParameter**プロパティで指定されたパラメーターを受け入れることもできます。汎用性を担保するために、このようにして乗数を指定します。バインディングコンバータは、コンバータパラメータに有効な**double**値をチェックします。

コンバータはリソースディクショナリーでインスタンス化されるため、複数のバインディング間で共有できます。

```xml
<local:DoubleToIntConverter x:Key="intConverter" />
```

3つのデータバインディングがこの1つのインスタンスを参照します。**Binding**マークアップ拡張に埋め込み**StaticResource**マークアップ拡張が含まれていることに注目してください。

```xml
<Label Text="{Binding Color.R,
                      Converter={StaticResource intConverter},
                      ConverterParameter=255,
                      StringFormat='R={0:X2}'}" />
```

こちらが結果です。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/Images/ListView3.png" title="Binding to a Collection with a DataTemplate and Converters" alt="Binding to a Collection with a DataTemplate and Converters" width="60%">

**ListView**は、基になるデータで動的に発生する可能性のある変更を処理するのにかなり洗練されていますが、特定の手順を実行する場合にのみ必要です。**ListView**の**ItemsSource**プロパティに割り当てられたアイテムのコレクションが実行時に変更された場合、つまりコレクションにアイテムが追加または削除され得る場合は、これらのアイテムの**ObservableCollection**クラスを使用します。**ObservableCollection**は**INotifyCollectionChanged**インターフェースを実装し、**ListView**は**CollectionChanged**イベントのハンドラをインストールします。

実行時にアイテム自体のプロパティが変更された場合、コレクション内のアイテムは**INotifyPropertyChanged**インターフェースを実装し、**PropertyChanged**イベントを使用してプロパティ値の変更を通知する必要があります。これはこのシリーズの次のパートで説明されています。[パート5 データバインディングからMVVMへ](#パート5-データバインディングからmvvmへ)

### まとめ
データバインディングは、ページ内の2つのオブジェクト間、またはビジュアルオブジェクトと元になるデータ間でプロパティをリンクする強力なメカニズムを提供します。しかし、アプリケーションがデータソースの処理を開始すると、著名なアプリケーションアーキテクチャパターンが有用なパラダイムとして浮上し始めます。これについては、[パート5 データバインディングからMVVMへ](#パート5-データバインディングからmvvmへ)を参照してください。

## [パート5 データバインディングからMVVMへ](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/)
**Model-View-ViewModelアーキテクチャの概要**

Model-View-ViewModel（MVVM）アーキテクチャパターンは、XAMLを念頭に置いて考案されました。このパターンソフトウェアの階層を3つに分離します。ビューと呼ばれるXAMLユーザインターフェース、Modelと呼ばれる基になるデータ、ViewModelと呼ばれるViewとModelの間の仲介者です。ViewとViewModelは、多くの場合、XAMLファイルで定義されたデータバインディングを介して接続されます。ViewのBindingContextは通常、ViewModelのインスタンスです。

### シンプルなViewModel
ViewModelsの導入として、最初にViewModelsが1つもないプログラムを見てみましょう。これまでに、新しいXML名前空間宣言を定義して、XAMLファイルが他のアセンブリのクラスを参照できるようにする方法を見てきました。**System**ネームスペースのXML名前空間宣言を定義するプログラムは次のとおりです。

```xml
xmlns:sys="clr-namespace:System;assembly=mscorlib"
```

このプログラムでは、**x:Static**を使用して静的なDateTime.Nowプロパティから現在の日付と時刻を取得し、その**DateTime**値を**StackLayout**の**BindingContext**に設定できます。

```xml
<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>
```

**BindingContext**は非常に特殊なプロパティです。要素に**BindingContext**を設定すると、その要素のすべての子によって継承されます。つまり、**StackLayout**のすべての子には同じ**BindingContext**があり、そのオブジェクトのプロパティへの単純なバインディングを含めることができます。**One-Shot DateTime**プログラムでは、2つの子に**DateTime**値のプロパティへのバインディングが含まれていますが、他の2つの子にはバインディングパスがないように見えます。これは、**DateTime**値自体が**StringFormat**に使用されていることを意味します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             x:Class="XamlSamples.OneShotDateTimePage"
             Title="One-Shot DateTime Page">

    <StackLayout BindingContext="{x:Static sys:DateTime.Now}"
                 HorizontalOptions="Center"
                 VerticalOptions="Center">

        <Label Text="{Binding Year, StringFormat='The year is {0}'}" />
        <Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
        <Label Text="{Binding Day, StringFormat='The day is {0}'}" />
        <Label Text="{Binding StringFormat='The time is {0:T}'}" />

    </StackLayout>
</ContentPage>
```

もちろん、大きな問題は、ページが最初に作成されたときに日付と時刻が一度設定され、変更されないことです。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/Images/OneShotDateTime.png" title="View Displaying Date and Time" alt="View Displaying Date and Time" width="60%">

XAMLファイルには、現在の時刻を常に示す時計が表示されますが、手助けするためのコードが必要です。MVVMの観点から考えると、ModelとViewModelは完全にコードで記述されたクラスです。Viewは、多くの場合、データバインディングを通じてViewModelで定義されたプロパティを参照するXAMLファイルです。

適切に設計すると、ModelはViewModelを知らず、ViewModelはViewをしらない状態になります。しかし、非常に多くの場合、プログラマは、ViewModelによって公開されるデータ型を、特定のユーザインターフェースに関連付けられたデータ型に調整します。たとえば、モデルが8ビット文字のASCII文字列を含むデータベースにアクセスする場合、ViewModelは、ユーザインターフェースでのUnicodeの排他使用に対応するために、これらの文字列をUnicode文字列に変換する必要があります。

MVVMの単純な例（ここに示すようなもの）では、モデルはまったくなく、パターンにはデータバインディングとリンクされたViewModelだけが含まれます。

ここでは、**DateTime**という名前のプロパティを持つ時計用のViewModelがありますが、毎秒**DateTime**プロパティが更新されます。

```csharp
using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
    class ClockViewModel : INotifyPropertyChanged
    {
        DateTime dateTime;

        public event PropertyChangedEventHandler PropertyChanged;

        public ClockViewModel()
        {
            this.DateTime = DateTime.Now;

            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    this.DateTime = DateTime.Now;
                    return true;
                });
        }

        public DateTime DateTime
        {
            set
            {
                if (dateTime != value)
                {
                    dateTime = value;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
                    }
                }
            }
            get
            {
                return dateTime;
            }
        }
    }
}
```

ViewModelsは一般的に**INotifyPropertyChanged**インタフェースを実装しています。つまり、プロパティのいずれかが変更されたときにクラスが**PropertyChanged**イベントを発生させます。Xamarin.Formsのデータバインディングメカニズムは、この**PropertyChanged**イベントにハンドラを添付します。したがって、プロパティが変更されたときに通知を受けて、ターゲットを新しい値で更新し続けることができます。

このViewModelに基づく時計は、次のように簡単にすることができます。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.ClockPage"
             Title="Clock Page">

    <Label Text="{Binding DateTime, StringFormat='{0:T}'}"
           FontSize="Large"
           HorizontalOptions="Center"
           VerticalOptions="Center">
        <Label.BindingContext>
            <local:ClockViewModel />
        </Label.BindingContext>
    </Label>
</ContentPage>
```

**ClockViewModel**がプロパティ要素タグを使用して**Label**の**BindingContext**にどのように設定されているかに注目してください。また、**ClockViewModel**を**Resources**コレクションでインスタンス化し、**StaticResource**マークアップ拡張を介して**BindingContext**に設定することもできます。コードビハインドファイルでもViewModelをインスタンス化できます。

**Label**の**Text**プロパティの**Binding**マークアップ拡張は、**DateTime**プロパティをフォーマットします。このように表示されます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/Images/Clock.png" title="View Displaying Date and Time via ViewModel" alt="View Displaying Date and Time via ViewModel" width="60%">

プロパティをピリオドで区切って、ViewModelのDateTimeプロパティの個々のプロパティにアクセスすることもできます。

```xml
<Label Text="{Binding DateTime.Second, StringFormat='{0}'}" … >
```

### インタラクティブMVVM
MVVMは、もとになるデータモデルに基づくインタラクティブビューの双方向データバインディングでよく使用されます。

**Color**値を**Hue**、**Saturation**、**Luminosity**の値に変換する**HslViewModel**というクラスがあります。その逆も同様です。

```csharp
using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
    public class HslViewModel : INotifyPropertyChanged
    {
        double hue, saturation, luminosity;
        Color color;

        public event PropertyChangedEventHandler PropertyChanged;

        public double Hue
        {
            set
            {
                if (hue != value)
                {
                    hue = value;
                    OnPropertyChanged("Hue");
                    SetNewColor();
                }
            }
            get
            {
                return hue;
            }
        }

        public double Saturation
        {
            set
            {
                if (saturation != value)
                {
                    saturation = value;
                    OnPropertyChanged("Saturation");
                    SetNewColor();
                }
            }
            get
            {
                return saturation;
            }
        }

        public double Luminosity
        {
            set
            {
                if (luminosity != value)
                {
                    luminosity = value;
                    OnPropertyChanged("Luminosity");
                    SetNewColor();
                }
            }
            get
            {
                return luminosity;
            }
        }

        public Color Color
        {
            set
            {
                if (color != value)
                {
                    color = value;
                    OnPropertyChanged("Color");

                    Hue = value.Hue;
                    Saturation = value.Saturation;
                    Luminosity = value.Luminosity;
                }
            }
            get
            {
                return color;
            }
        }

        void SetNewColor()
        {
            Color = Color.FromHsla(Hue, Saturation, Luminosity);
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
```

**Hue**、**Saturation**、**Luminosity**のプロパティを変更すると、**Color**プロパティが変更され、**Color**を変更すると、他の3つのプロパティが変更されます。これは、プロパティが実際に変更されない限りクラスが**PropertyChanged**イベントを呼び出さないことを除いて、無限ループのように見えるかもしれません。そうでなけば制御不能なフィードバックループを終了させます。

次のXAMLファイルには、**Color**プロパティがViewModelの**Color**プロパティにバインドされた**BoxView**と、**Hue**、**Saturation**、**Luminosity**プロパティにバインドされた3つの**Slider**および3つの**Label**ビューが含まれています。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.HslColorScrollPage"
             Title="HSL Color Scroll Page">
    <ContentPage.BindingContext>
        <local:HslViewModel Color="Aqua" />
    </ContentPage.BindingContext>

    <StackLayout Padding="10, 0">
        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Hue, Mode=TwoWay}" />

        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Saturation, Mode=TwoWay}" />

        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Luminosity, Mode=TwoWay}" />
    </StackLayout>
</ContentPage>
```

各**Label**のバインディングは、デフォルトの**OneWay**です。値を表示するのにだけ必要です。しかし、各**Slider**のバインディングは**TwoWay**です。これにより、**Slider**をViewModelから初期化することができます。ViewModelがインスタンス化されると、**Color**プロパティが**Blue**に設定されていることに注意してください。しかし、**Slider**を変更すると、ViewModelのプロパティの新しい値を設定する必要があり、ViewModelは新しい色を計算します。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/Images/HslColorScroll.png" title="MVVM using Two-Way Data Bindings" alt="MVVM using Two-Way Data Bindings" width="60%">

### ViewModelでのコマンド
多くの場合、MVVMパターンはデータ項目の操作に制限されています。ViewのユーザインターフェースオブジェクトはViewModelのデータオブジェクトに対応しています。

しかし、ViewにViewModelのさまざまなアクションをトリガーするボタンが含まれている必要があることがあります。しかし、ViewModelにはボタンの**Clicked**ハンドラが含まれてはいけません。これは、ViewModelを特定のユーザインターフェースのパラダイムに結びつけてしまうためです。

ViewModelを特定のユーザインターフェースオブジェクトからより独立させ、かつViewModel内でメソッドを呼び出せるようにするために、*command*インタフェースが存在します。このコマンドインタフェースは、Xamarin.Formsの以下の要素でサポートされています。

* **Button**
* **MenuItem**
* **ToolbarItem**
* **SearchBar**
* **TextCell** (と **ImageCell**)
* **ListView**
* **TapGestureRecognizer**

**SearchBar**と**ListView**要素を除いて、これらの要素は2つのプロパティを定義します。

* **System.Windows.Input.ICommand**型の**Command**
* **Object**型の**CommandParameter**

**SearchBar**は**SearchCommand**と**SearchCommandParameter**プロパティを定義し、**ListView**は**ICommand型**の**RefreshCommand**プロパティを定義します。

**ICommand**インターフェースは、2つのメソッドと1つのイベントを定義します。

* **void Execute(object arg)**
* **bool CanExecute(object arg)**
* **event EventHandler CanExecuteChanged**

ViewModelは、**ICommand**型のプロパティを定義できます。これらのプロパティは、各**Button**やその他の要素の**Command**プロパティ、またはおそらくこのインターフェースを実装するカスタムビューにバインドできます。オプションで、このViewModelプロパティにバインドされている個々の**Button**オブジェクト（またはその他の要素）を識別するために**CommandParameter**プロパティを設定できます。内部的には、ユーザーが**Button**をタップして**CommandParameter**を**Execute**メソッドに渡すと、**Button**は**Execute**メソッドを呼び出します。

**CanExecute**メソッドと**CanExecuteChanged**イベントは、**Button**タップが現在無効である場合に使用されます。この場合、**Button**自体を無効にする必要があります。**Button**は、**Command**プロパティが最初に設定され、**CanExecuteChanged**イベントが発生するたびに**CanExecute**を呼び出します。**CanExecute**が**false**を返すと、**Button**は自身を無効にし、**Execute**呼び出しを生成しません。

ViewModelにコマンドを追加する際の助けとして、Xamarin.Formsは**ICommand**を実装する2つのクラスを定義しています。**Command**と**Command<T>**（**T**は**Execute**と**CanExecute**の引数の型）です。これらの2つのクラスは、いくつかのコンストラクタと、ViewModelが**CanExecuteChanged**イベントを発生させる**Command**オブジェクトを強制的に呼び出すことができる**ChangeCanExecute**メソッドを定義します。

電話番号を入力するための単純なキーパッドのViewModelがあります。**Execute**メソッドと**CanExecute**メソッドは、コンストラクタ内でラムダ関数として定義されていることに注意してください。

```csharp
using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace XamlSamples
{
    class KeypadViewModel : INotifyPropertyChanged
    {
        string inputString = "";
        string displayText = "";
        char[] specialChars = { '*', '#' };

        public event PropertyChangedEventHandler PropertyChanged;

        // Constructor
        public KeypadViewModel()
        {
            AddCharCommand = new Command<string>((key) =>
                {
                    // Add the key to the input string.
                    InputString += key;
                });

            DeleteCharCommand = new Command(() =>
                {
                    // Strip a character from the input string.
                    InputString = InputString.Substring(0, InputString.Length - 1);
                },
                () =>
                {
                    // Return true if there's something to delete.
                    return InputString.Length > 0;
                });
        }

        // Public properties
        public string InputString
        {
            protected set
            {
                if (inputString != value)
                {
                    inputString = value;
                    OnPropertyChanged("InputString");
                    DisplayText = FormatText(inputString);

                    // Perhaps the delete button must be enabled/disabled.
                    ((Command)DeleteCharCommand).ChangeCanExecute();
                }
            }

            get { return inputString; }
        }

        public string DisplayText
        {
            protected set
            {
                if (displayText != value)
                {
                    displayText = value;
                    OnPropertyChanged("DisplayText");
                }
            }
            get { return displayText; }
        }

        // ICommand implementations
        public ICommand AddCharCommand { protected set; get; }

        public ICommand DeleteCharCommand { protected set; get; }

        string FormatText(string str)
        {
            bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
            string formatted = str;

            if (hasNonNumbers || str.Length < 4 || str.Length > 10)
            {
            }
            else if (str.Length < 8)
            {
                formatted = String.Format("{0}-{1}",
                                          str.Substring(0, 3),
                                          str.Substring(3));
            }
            else
            {
                formatted = String.Format("({0}) {1}-{2}",
                                          str.Substring(0, 3),
                                          str.Substring(3, 3),
                                          str.Substring(6));
            }
            return formatted;
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
```

このViewModelは、**AddCharCommand**プロパティが**CommandParameter**によって識別されるいくつかのボタン（またはコマンドインターフェースを持つもの）の**Command**プロパティにバインドされていることを前提としています。これらのボタンは、**InputString**プロパティに文字を追加し、**DisplayText**プロパティの電話番号として書式設定されます。

**DeleteCharCommand**という名前の**ICommand**型の2番目のプロパティもあります。これはバックスペースボタンにバインドされていますが、削除する文字がない場合はボタンを無効にする必要があります。

次のキーパッドは視覚的に洗練されていません。その代わりに、マークアップはコマンド・インターフェースの使用をより明確に示すために最小限に抑えられています。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.KeypadPage"
             Title="Keypad Page">

    <Grid HorizontalOptions="Center"
          VerticalOptions="Center">
        <Grid.BindingContext>
            <local:KeypadViewModel />
        </Grid.BindingContext>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
        </Grid.ColumnDefinitions>

        <!-- Internal Grid for top row of items -->
        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Frame Grid.Column="0"
                   OutlineColor="Accent">
                <Label Text="{Binding DisplayText}" />
            </Frame>

            <Button Text="⇦"
                    Command="{Binding DeleteCharCommand}"
                    Grid.Column="1"
                    BorderWidth="0" />
        </Grid>

        <Button Text="1"
                Command="{Binding AddCharCommand}"
                CommandParameter="1"
                Grid.Row="1" Grid.Column="0" />

        <Button Text="2"
                Command="{Binding AddCharCommand}"
                CommandParameter="2"
                Grid.Row="1" Grid.Column="1" />

        <Button Text="3"
                Command="{Binding AddCharCommand}"
                CommandParameter="3"
                Grid.Row="1" Grid.Column="2" />

        <Button Text="4"
                Command="{Binding AddCharCommand}"
                CommandParameter="4"
                Grid.Row="2" Grid.Column="0" />

        <Button Text="5"
                Command="{Binding AddCharCommand}"
                CommandParameter="5"
                Grid.Row="2" Grid.Column="1" />

        <Button Text="6"
                Command="{Binding AddCharCommand}"
                CommandParameter="6"
                Grid.Row="2" Grid.Column="2" />

        <Button Text="7"
                Command="{Binding AddCharCommand}"
                CommandParameter="7"
                Grid.Row="3" Grid.Column="0" />

        <Button Text="8"
                Command="{Binding AddCharCommand}"
                CommandParameter="8"
                Grid.Row="3" Grid.Column="1" />

        <Button Text="9"
                Command="{Binding AddCharCommand}"
                CommandParameter="9"
                Grid.Row="3" Grid.Column="2" />

        <Button Text="*"
                Command="{Binding AddCharCommand}"
                CommandParameter="*"
                Grid.Row="4" Grid.Column="0" />

        <Button Text="0"
                Command="{Binding AddCharCommand}"
                CommandParameter="0"
                Grid.Row="4" Grid.Column="1" />

        <Button Text="#"
                Command="{Binding AddCharCommand}"
                CommandParameter="#"
                Grid.Row="4" Grid.Column="2" />
    </Grid>
</ContentPage>
```

このマークアップに表示される最初の**Button**の**Command**プロパティは、**DeleteCharCommand**にバインドされています。残りはボタン面に表示される文字と同じ**CommandParameter**を持つ**AddCharCommand**にバインドされます。プログラムの実行結果は次のとおりです。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/Images/KeyPad.png" title="Calculator using MVVM and Commands" alt="Calculator using MVVM and Commands" width="60%">

#### 非同期メソッドの呼び出し
コマンドは、非同期メソッドを呼び出すこともできます。これは、Executeメソッドを指定するときに**async**キーワードと**await**キーワードを使用することによって実現されます。

```csharp
DownloadCommand = new Command (async () => await DownloadAsync ());
```

これは、**DownloadAsync**メソッドが**Task**であり、待機する必要があることを示します。

```csharp
async Task DownloadAsync ()
{
    await Task.Run (() => Download ());
}

void Download ()
{
    ...
}
```

### ナビゲーションメニューの実装
この一連の記事のすべてのソースコードを含む[XamlSamples](https://developer.xamarin.com/samples/xamarin-forms/XamlSamples/)プログラムは、そのホームページにViewModelを使用します。このViewModelは、各サンプルページのタイプ、タイトル、および短い説明を含む**Type**、**Title**、**Description**という3つのプロパティを持つ短いクラスの定義です。さらに、ViewModelは、プログラム内のすべてのページのコレクションである**All**という名前の静的プロパティを定義します。

```csharp
public class PageDataViewModel
{
    public PageDataViewModel(Type type, string title, string description)
    {
        Type = type;
        Title = title;
        Description = description;
    }

    public Type Type { private set; get; }

    public string Title { private set; get; }

    public string Description { private set; get; }

    static PageDataViewModel()
    {
        All = new List<PageDataViewModel>
        {
            // Part 1. Getting Started with XAML
            new PageDataViewModel(typeof(HelloXamlPage), "Hello, XAML",
                                  "Display a Label with many properties set"),

            new PageDataViewModel(typeof(XamlPlusCodePage), "XAML + Code",
                                  "Interact with a Slider and Button"),

            // Part 2. Essential XAML Syntax
            new PageDataViewModel(typeof(GridDemoPage), "Grid Demo",
                                  "Explore XAML syntax with the Grid"),

            new PageDataViewModel(typeof(AbsoluteDemoPage), "Absolute Demo",
                                  "Explore XAML syntax with AbsoluteLayout"),

            // Part 3. XAML Markup Extensions
            new PageDataViewModel(typeof(SharedResourcesPage), "Shared Resources",
                                  "Using resource dictionaries to share resources"),

            new PageDataViewModel(typeof(StaticConstantsPage), "Static Constants",
                                  "Using the x:Static markup extensions"),

            new PageDataViewModel(typeof(RelativeLayoutPage), "Relative Layout",
                                  "Explore XAML markup extensions"),

            // Part 4. Data Binding Basics
            new PageDataViewModel(typeof(SliderBindingsPage), "Slider Bindings",
                                  "Bind properties of two views on the page"),

            new PageDataViewModel(typeof(SliderTransformsPage), "Slider Transforms",
                                  "Use Sliders with reverse bindings"),

            new PageDataViewModel(typeof(ListViewDemoPage), "ListView Demo",
                                  "Use a ListView with data bindings"),

            // Part 5. From Data Bindings to MVVM
            new PageDataViewModel(typeof(OneShotDateTimePage), "One-Shot DateTime",
                                  "Obtain the current DateTime and display it"),

            new PageDataViewModel(typeof(ClockPage), "Clock",
                                  "Dynamically display the current time"),

            new PageDataViewModel(typeof(HslColorScrollPage), "HSL Color Scroll",
                                  "Use a view model to select HSL colors"),

            new PageDataViewModel(typeof(KeypadPage), "Keypad",
                                  "Use a view model for numeric keypad logic")
        };
    }

    public static IList<PageDataViewModel> All { private set; get; }
}
```

**MainPage**のXAMLファイルは、**ItemsSource**プロパティが**All**プロパティに設定され、各ページの**Title**プロパティと**Description**プロパティを表示する**TextCell**を含む**ListBox**を定義します。

```xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.MainPage"
             Padding="5, 0"
             Title="XAML Samples">

    <ListView ItemsSource="{x:Static local:PageDataViewModel.All}"
              ItemSelected="OnListViewItemSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding Title}"
                          Detail="{Binding Description}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

```

ページはスクロール可能なリストで表示されます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/Images/MainPage.png" title="Scrollable list of pages" alt="Scrollable list of pages" width="60%">

コードビハインドファイルのハンドラは、ユーザが項目を選択するとトリガされます。ハンドラは**ListBox**の**SelectedItem**プロパティを**null**に戻し、選択したページをインスタンス化してそのページに移動します。

```csharp
private async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)
{
    (sender as ListView).SelectedItem = null;

    if (args.SelectedItem != null)
    {
        PageDataViewModel pageData = args.SelectedItem as PageDataViewModel;
        Page page = (Page)Activator.CreateInstance(pageData.Type);
        await Navigation.PushAsync(page);
    }
}
```

### まとめ
XAMLは、特にデータバインディングとMVVMを使用する場合に、Xamarin.Formsアプリケーションでユーザインターフェースを定義するための強力なツールです。その結果、きれいで、エレガントで、ツールで表現可能なユーザインターフェースが表現され、コード内のすべてのバックグラウンドサポートが得られます。

# [XAMLコンパイル](https://developer.xamarin.com/guides/xamarin-forms/xaml/xamlc/)
**XAMLコンパイラを使用してXamarin.Formsアプリケーションのパフォーマンスを向上させる**

XAMLは、XAMLコンパイラ（XAMLC）で中間言語（IL）に直接コンパイルすることもできます。

XAMLCには多くの利点があります。

* XAMLのコンパイル時チェックを実行し、ユーザーにエラーを通知します。
* XAML要素のロードおよびインスタンス化時間の一部を削減します。
* .xamlファイルを含まなくなることで、最終アセンブリのファイルサイズを縮小するのに役立ちます。

下位互換性を確保するため、XAMLCはデフォルトで無効になっています。**XamlCompilation**属性を追加することで、アセンブリレベルとクラスレベルの両方で有効にすることができます。

次のコード例は、アセンブリレベルでXAMLCを有効にする方法を示しています。

```csharp
using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
  ...
}
```

この例では、**PhotoApp**名前空間に含まれるすべてのXAMLのコンパイル時チェックが実行され、実行時ではなくコンパイル時にXAMLエラーが報告されます。**XamlCompilation**属性の**assembly**プレフィックスは、属性がアセンブリ全体に適用されることを指定します。

次のコード例は、クラスレベルでXAMLCを有効にする方法を示しています。

```csharp
using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
  ...
}
```

この例では、HomePageクラスのXAMLのコンパイル時チェックが実行され、コンパイルプロセスの一部としてエラーがレポートされます。

**XamlCompilationOptions**列挙体は、Xamarin.Forms.Xaml名前空間にあり、使用するためにインポートする必要があります。


# [Xamarin.Forms向けのXAMLプレビューア](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/)
**タイピング時にレンダリングされるXamarin.Formsレイアウトを見てみましょう**

## 要件
プロジェクトには、XAMLプレビューアが機能するための最新のXamarin.Forms NuGetパッケージが必要です。Androidアプリをプレビューするには、[JDK 1.8 x64](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)が必要です。

[リリースノート](https://developer.xamarin.com/releases/studio/xamarin.studio_6.2/xamarin.studio_6.2/#Xamarin_Forms_Previewer)にはさらに詳しい情報があります。

## 入門

### MacでVisual Studio for Macを使用する場合
**Preview**ボタンは、XAMLファイルを右クリックし、**Open With** > **XAML Viewer**を選択することで、エディタに表示できます。 XAMLドキュメントウィンドウの右上隅にある**Preview**ボタンを押すと、プレビューウィンドウが表示または非表示になります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/Images/xamlp-list-sml.png" title="ListView control preview in Visual Studio for Mac" alt="ListView control preview in Visual Studio for Mac" width="60%">

### WindowsでVisual Studioを使用する場合
Visual Studioの**View** > **Other Windows** > **Xamarin.Forms Previewer**メニューを選択して、プレビューウィンドウを開きます。**Window** > **New Vertical Tab Group**メニューを使ってサイドバイサイドで配置します。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/Images/xamlp-list-vs-sml.png" title="ListView control preview in Visual Studio" alt="ListView control preview in Visual Studio" width="60%">

## XAMLプレビューオプション
プレビューペインの上部にあるオプションは次のとおりです。

* **Phone** – 電話機サイズの画面でレンダリングします
* **Tablet** – タブレットサイズのスクリーンでレンダリングします（ペインの右下にズームコントロールがあります）
* **Android** – Androidバージョンの画面を表示します
* **iOS** – iOSバージョンの画面を表示します
* **Portait** (アイコン) – プレビューに縦向きを使用します
* **Landscape** (アイコン) – プレビューに横向きを使用します

## デザイン時データの追加
一部のレイアウトは、ユーザインターフェースコントロールにバインドされたデータなしでは視覚化しにくい場合があります。プレビューをより便利にするには、コードビハインドまたはXAMLを使用してバインディングコンテキストをハードコードすることによって、いくつかの静的データをコントロールに割り当てます。

XAMLの静的なViewModelにバインドする方法については、[James Montemagnoのブログ記事のデザイン時データの追加](https://montemagno.com/xamarinforms-xaml-previewer-design-time-data/)を参照してください。

## トラブルシューティング
問題が発生した場合は、以下のissueと[Xamarin Forums](https://forums.xamarin.com/categories/xamarin-forms)を確認してください。

### XAMLプレビューが表示されない
以下を確認してください。

* XAMLファイルをプレビューする前にプロジェクトをビルド（コンパイル）する必要があります。
* デザイナーエージェントは、XAMLファイルを初めてプレビューするときにセットアップする必要があります。準備が整うまで、進行状況インジケータが進行状況メッセージと共にプレビューアに表示されます。
* XAMLファイルを閉じてもう一度開きます。

### 無効なXAML：プレビューを作成する前にAndroidプロジェクトをビルドする必要があります
XAMLプレビューアでは、ページを表示する前にプロジェクトをビルドする必要があります。プレビューペインの上部に以下のエラーが表示された場合は、アプリケーションをリビルドしてもう一度やり直してください。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/Images/error-not-built-sml.png" title="Error message: project must be built first" alt="Error message: project must be built first">

# [XAML名前空間](https://developer.xamarin.com/guides/xamarin-forms/xaml/namespaces/)

**型を参照するためのXAML名前空間宣言**

XAMLは、名前空間宣言にxmlns XML属性を使用します。この、記事では、XAML名前空間の構文を紹介し、型にアクセスするためにXAML名前空間を宣言する方法を示します。

## 概要
XAMLファイルのルート要素内には常に2つのXAML名前空間宣言があります。1つ目は、次のXAMLコードの例に示すように、デフォルトの名前空間を定義します。

```xml
xmlns="http://xamarin.com/schemas/2014/forms"
```

デフォルトの名前空間では、XAMLファイル内で定義されたプレフィックスのない要素は、**[ContentPage](https://developer.xamarin.com/api/type/Xamarin.Forms.ContentPage/)**などのXamarin.Formsクラスを参照します。

2番目の名前空間宣言では、次のXAMLコードの例に示すように、**x**プレフィックスが使用されます。

```xml
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
```

XAMLは、プレフィックスを使用して、デフォルト以外の名前空間を宣言します。プレフィックスは、名前空間内の型を参照するときに使用されます。**x**名前空間宣言は、プレフィックス**x**を持つXAML内で定義された要素が、XAMLに固有の要素および属性（特に2009 XAML仕様）に使用されることを指定します。

次の表は、Xamarin.Formsでサポートされている**x**名前空間の属性の概要を示しています。

|構成|説明|
|:--|:--|
|**x:Arguments**|デフォルト以外のコンストラクタ、またはファクトリメソッドオブジェクト宣言のコンストラクタ引数を指定します。|
|**x:Class**|XAMLで定義されたクラスの名前空間とクラス名を指定します。クラス名はコードビハインドファイルのクラス名と一致する必要があります。この構文は、XAMLファイルのルート要素にのみ記述できます。|
|**x:FactoryMethod**|オブジェクトを初期化するために使用できるファクトリメソッドを指定します。|
|**x:Key**|**ResourceDictionary**内の各リソースの一意のユーザー定義キーを指定します。キーの値はXAMLリソースを取得するために使用され、通常は**StaticResource**マークアップ拡張の引数として使用されます。|
|**x:Name**|XAML要素の実行時オブジェクト名を指定します。**x:Name**の設定は、コード内で変数を宣言するのと似ています。|
|**x:TypeArguments**|ジェネリック型のコンストラクタへのジェネリック型の引数を指定します。|

**x:Arguments**、**x:FactoryMethod**、**x:TypeArguments**の各属性の詳細については、[XAMLでの引数の受け渡し](#xamlでの引数の受け渡し)を参照してください。

XAMLでは、名前空間宣言は親要素から子要素に継承されます。したがって、XAMLファイルのルート要素に名前空間を定義すると、そのファイル内のすべての要素が名前空間宣言を継承します。

## 型の名前空間宣言
XAMLで型を参照するには、接頭辞付きのXAML名前空間を宣言し、CLR（Common Language Runtime）名前空間名を指定する名前空間宣言と、オプションでアセンブリ名を指定します。これは、名前空間宣言内の次のキーワードの値を定義することによって実現されます。

* **clr-namespace:** か **using:** ー XAML要素として公開する型を含むアセンブリ内で宣言されたCLR名前空間。このキーワードは必須です。
* **assembly=** ー 参照されるCLR名前空間を含むアセンブリ。この値は、ファイル拡張子のないアセンブリの名前です。アセンブリへのパスは、アセンブリを参照するXAMLファイルを含むプロジェクトファイル内の参照として設定する必要があります。**clr-namespace**の値が型を参照するアプリケーションコードと同じアセンブリ内にある場合、このキーワードは省略できます。

**clr-namespace**もしくは**using**トークンと値を分離する文字はコロンですが、**assembly**トークンとその値を分離する文字は等号です。2つのトークンの間に使用する文字はセミコロンです。

次のコード例は、XAML名前空間宣言を示しています。

```xml
<ContentPage ... xmlns:local="clr-namespace:HelloWorld" ...>
  ...
</ContentPage>
```

あるいは、これは次のように書くことができます。

```xml
<ContentPage ... xmlns:local="using:HelloWorld" ...>
  ...
</ContentPage>
```

**local**プレフィックスは、名前空間内の型がアプリケーションに対してローカルであることを示すために使用される規則です。型が別のアセンブリにある場合は、次のXAMLコードの例に示すように、アセンブリ名を名前空間宣言にも定義する必要があります。

```xml
<ContentPage ... xmlns:behaviors="clr-namespace:Behaviors;assembly=BehaviorsLibrary" ...>
  ...
</ContentPage>
```

次のXAMLコード例に示すように、インポートされた名前空間から型のインスタンスを宣言するときに、名前空間プレフィックスが指定されます。

```xml
<ListView ...>
  <ListView.Behaviors>
    <behaviors:EventToCommandBehavior EventName="ItemSelected" ... />
  </ListView.Behaviors>
</ListView>
```


## まとめ
この記事では、XAML名前空間の構文を紹介し、型にアクセスするためにXAML名前空間を宣言する方法を示しました。XAMLは名前空間宣言にxmlns XML属性を使用し、プレフィックス付きのXAML名前空間を宣言することによってXAMLで型を参照できます。

# [XAMLでの引数の受け渡し](https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/)

この記事では、デフォルト以外のコンストラクターに引数を渡したり、ファクトリーメソッドを呼び出したり、汎用引数の型を指定するために使用できるXAML属性の使用方法について説明します。

## 概要
引数を必要とするコンストラクタを使用してオブジェクトをインスタンス化するか、静的な作成メソッドを呼び出す必要があることがよくあります。これは、**x:Argument**および**x:FactoryMethod**属性を使用してXAMLで実現できます。

* x:Argument属性は、デフォルト以外のコンストラクタ、またはファクトリーメソッドオブジェクト宣言のコンストラクタ引数を指定するために使用されます。詳細については、[コンストラクタ引数の受け渡し](#コンストラクタ引数の受け渡し)を参照してください。
* **x:FactoryMethod**属性は、オブジェクトの初期化に使用できるファクトリメソッドを指定するために使用されます。詳細については、[ファクトリーメソッドの呼び出し](#ファクトリーメソッドの呼び出し)を参照してください。

さらに、**x:TypeArguments**属性を使用して、ジェネリック型のコンストラクタへのジェネリック型引数を指定できます。詳細については、[ジェネリック型引数の指定](#ジェネリック型引数の指定)を参照してください。

## [コンストラクタ引数の受け渡し](https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/#constructor_arguments)
引数は、**x:Argument**属性を使用して、デフォルト以外のコンストラクタに渡すことができます。各コンストラクタ引数は、引数の型を表すXML要素内で区切られなければなりません。Xamarin.Formsは、基本型に対して次の要素をサポートしています。

* **x:Object**
* **x:Boolean**
* **x:Byte**
* **x:Int16**
* **x:Int32**
* **x:Int64**
* **x:Single**
* **x:Double**
* **x:Decimal**
* **x:Char**
* **x:String**
* **x:TimeSpan**
* **x:Array**
* **x:DateTime**

次のコード例は、**x:Arguments**属性と3つのColorコンストラクタを使用する方法を示しています。

```xml
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color>
      <x:Arguments>
        <x:Double>0.9</x:Double>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color>
      <x:Arguments>
        <x:Double>0.25</x:Double>
        <x:Double>0.5</x:Double>
        <x:Double>0.75</x:Double>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color>
      <x:Arguments>
        <x:Double>0.8</x:Double>
        <x:Double>0.5</x:Double>
        <x:Double>0.2</x:Double>
        <x:Double>0.5</x:Double>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
```

**x:Arguments**タグ内の要素の数とこれらの要素の型は、**[Color](https://developer.xamarin.com/api/type/Xamarin.Forms.Color/)**コンストラクタの1つと一致する必要があります。１つのパラメータを持つ**Color**[コンストラクタ](https://developer.xamarin.com/api/constructor/Xamarin.Forms.Color.Color/p/System.Double/)では、0（黒）から1（白）までのグレースケール値が必要です。3つのパラメータを持つ**Color**[コンストラクタ](https://developer.xamarin.com/api/constructor/Xamarin.Forms.Color.Color/p/System.Double/System.Double/System.Double/)では、0〜1の範囲の赤、緑、青の値が必要です。4つのパラメータを持つ**Color**[コンストラクタ](https://developer.xamarin.com/api/constructor/Xamarin.Forms.Color.Color/p/System.Double/System.Double/System.Double/System.Double/)は、4つ目のパラメータとしてアルファチャンネルを追加します。

次のスクリーンショットは、指定された引数値を持つ各**[Color](https://developer.xamarin.com/api/type/Xamarin.Forms.Color/)**コンストラクタを呼び出した結果を示しています。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/Images/passing-arguments.png" title="BoxView.Color specified with x:Arguments" alt="BoxView.Color specified with x:Arguments" width="60%">

## [ファクトリーメソッドの呼び出し](https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/#factory_methods)
ファクトリーメソッドは、**x:FactoryMethod**属性を使用してメソッドの名前を指定し、**x:Arguments**属性を使用して引数を指定することで、XAMLで呼び出すことができます。ファクトリーメソッドは、メソッドを定義するクラスまたは構造体と同じ型のオブジェクトまたは値を返す**public static**メソッドです。

**[Color](https://developer.xamarin.com/api/type/Xamarin.Forms.Color/)**構造体にはいくつかのファクトリメソッドが定義されています。次のコード例は、これらの3つを呼び出す方法を示しています。

```xml
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color x:FactoryMethod="FromRgba">
      <x:Arguments>
        <x:Int32>192</x:Int32>
        <x:Int32>75</x:Int32>
        <x:Int32>150</x:Int32>
        <x:Int32>128</x:Int32>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color x:FactoryMethod="FromHsla">
      <x:Arguments>
        <x:Double>0.23</x:Double>
        <x:Double>0.42</x:Double>
        <x:Double>0.69</x:Double>
        <x:Double>0.7</x:Double>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
  <BoxView.Color>
    <Color x:FactoryMethod="FromHex">
      <x:Arguments>
        <x:String>#FF048B9A</x:String>
      </x:Arguments>
    </Color>
  </BoxView.Color>
</BoxView>
```

**x:Arguments**タグ内の要素の数とこれらの要素の型は、呼び出されるファクトリーメソッドの引数と一致する必要があります。**[FromRgba](https://developer.xamarin.com/api/member/Xamarin.Forms.Color.FromRgba/p/System.Int32/System.Int32/System.Int32/System.Int32/)**ファクトリーメソッドには、赤、緑、青、およびアルファ値をそれぞれ表す0〜255の4つの**[Int32](https://developer.xamarin.com/api/type/System.Int32/)**パラメータが必要です。**[FromHsla](https://developer.xamarin.com/api/member/Xamarin.Forms.Color.FromHsla/p/System.Double/System.Double/System.Double/System.Double/)**ファクトリーメソッドは、色相、彩度、明度、およびアルファ値をそれぞれ表す0〜1の4つの**[Double](https://developer.xamarin.com/api/type/System.Double/)**パラメータを必要とします。**[FromHex](https://developer.xamarin.com/api/member/Xamarin.Forms.Color.FromHex/p/System.String/)**ファクトリーメソッドには、16進数（A）のRGBカラーを表す**[String](https://developer.xamarin.com/api/type/System.String/)**が必要です。

次のスクリーンショットは、指定された引数値を持つ各**[Color](https://developer.xamarin.com/api/type/Xamarin.Forms.Color/)**ファクトリーメソッドを呼び出した結果を示しています。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/Images/factory-methods.png" title="BoxView.Color specified with x:FactoryMethod and x:Arguments" alt="BoxView.Color specified with x:FactoryMethod and x:Arguments" width="60%">

## [ジェネリック型引数の指定](https://developer.xamarin.com/guides/xamarin-forms/xaml/passing-arguments/#generic_type_arguments)
ジェネリック型のコンストラクタのジェネリック型引数は、次のコード例に示すように、**x:TypeArguments**属性を使用して指定できます。

```xml
<ContentPage ...>
  <StackLayout>
    <StackLayout.Margin>
      <OnPlatform x:TypeArguments="Thickness">
        <On Platform="iOS" Value="0,20,0,0" />
        <On Platform="Android" Value="5, 10" />
        <On Platform="WinPhone, Windows" Value="10" />
      </OnPlatform>
    </StackLayout.Margin>
  </StackLayout>
</ContentPage>
```

**[OnPlatform](https://developer.xamarin.com/api/type/Xamarin.Forms.OnPlatform%3CT%3E/)**クラスはジェネリッククラスであり、ターゲットタイプと一致する**x:TypeArguments**属性でインスタンス化する必要があります。**[On](https://developer.xamarin.com/api/type/Xamarin.Forms.On/)**クラスでは、**[Platform](https://developer.xamarin.com/api/property/Xamarin.Forms.On.Platform/)**属性は単一の**string**値、または複数のカンマ区切りの**string**値を受け入れることができます。この例では、**[StackLayout.Margin](https://developer.xamarin.com/api/property/Xamarin.Forms.View.Margin/)**プロパティがプラットフォーム固有の**[Thickness](https://developer.xamarin.com/api/type/Xamarin.Forms.Thickness/)**に設定されています。

## まとめ
この記事では、デフォルト以外のコンストラクターに引数を渡したり、ファクトリーメソッドを呼び出したり、ジェネリック引数の型を指定するために使用できるXAML属性の使用方法について説明しました。

# [バインダブルプロパティ](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/)

**バインディングを許可するプロパティの作成**

Xamarin.Formsでは、共通言語ランタイム（CLR）プロパティの機能がバインダブルプロパティによって拡張されています。バインダブルプロパティは特殊なタイプのプロパティです。プロパティの値はXamarin.Formsプロパティシステムによって追跡されます。この記事では、バインダブルプロパティの概要を紹介し、バインダブルプロパティを作成、使用する方法を示します。

## 概要
バインダブルプロパティは、プロパティをフィールドでサポートするのではなく、**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**型でプロパティをサポートすることにより、CLRプロパティの機能を拡張します。バインダブルプロパティの目的は、親子関係で設定されたデータバインディング、スタイル、テンプレート、値をサポートするプロパティシステムを提供することです。さらに、バインダブルプロパティは、デフォルト値、プロパティ値の検証、プロパティの変更を監視するコールバックを提供できます。

プロパティは、以下の機能の1つ以上をサポートするために、バインダブルプロパティとして実装する必要があります。

* データバインディングの有効な*target*プロパティとして機能
* **[style](https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/)**を使用してプロパティを設定
* プロパティの型のデフォルトとは異なるデフォルトのプロパティー値の提供
* プロパティの値の検証

Xamarin.Formsのバインダブルプロパティなプロパティの例には、**[Label.Text](https://developer.xamarin.com/api/property/Xamarin.Forms.Label.Text/)**、**[Button.BorderRadius](https://developer.xamarin.com/api/property/Xamarin.Forms.Button.BorderRadius/)**、**[StackLayout.Orientation](https://developer.xamarin.com/api/property/Xamarin.Forms.StackLayout.Orientation/)**があります。各バインダブルプロパティには、同じクラスで公開されるバインダブルプロパティの識別子である**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**型の対応する**public static readonly**プロパティがあります。たとえば、**Label.Text**プロパティの対応するバインド可能なプロパティ識別子は**[Label.TextProperty](https://developer.xamarin.com/api/field/Xamarin.Forms.Label.TextProperty/)**です。

## [バインダブルプロパティの作成と使用](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/#consuming-bindable-property)
バインダブルプロパティを作成するプロセスは、次のとおりです。

1. **[BindableProperty.Create](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドオーバーロードのいずれかを使用して**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスを作成します。
2. **[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスのプロパティアクセサを定義します。

すべての**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスは、UIスレッドで作成する必要があります。これは、UIスレッドで実行されるコードだけが**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**の値を取得または設定できることを意味します。しかし、**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスは、**[Device.BeginInvokeOnMainThread](https://developer.xamarin.com/api/member/Xamarin.Forms.Device.BeginInvokeOnMainThread/p/System.Action/)**メソッドを使用してUIスレッドにマーシャリングすることによって、他のスレッドからアクセスできます。

### プロパティの作成
**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスを作成するには、含まれるクラスが**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**クラスから派生する必要があります。しかし、**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**クラスはクラス階層の上位です。そのため、ユーザインターフェース機能に使用されるクラスの大半は**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**をサポートしています。

バインダブルプロパティは、**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**型の**public static readonly**プロパティを宣言することによって作成できます。バインダブルプロパティは、**[BindableProperty.Create](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドのオーバーロードのいずれかの戻り値に設定する必要があります。宣言は、**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**派生クラスの本体内にある必要がありますが、メンバー定義の外にある必要があります。

**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**を作成する際には、少なくとも次のパラメータとともに識別子を指定する必要があります。

* **[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**の名前
* プロパティの型
* 所有オブジェクトの型
* プロパティーのデフォルト値。これにより、プロパティが設定されていない場合に常に特定のデフォルト値が返され、プロパティの型のデフォルト値と異なる可能性があります。デフォルト値は、バインダブルプロパティに対して**[ClearValue](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableObject.ClearValue/p/Xamarin.Forms.BindableProperty/)**メソッドが呼び出されたときに復元されます。

次のコードは、4つの必須パラメータの識別子と値を持つバインダブルプロパティの例を示しています。

```csharp
public static readonly BindableProperty EventNameProperty =
  BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null);
```

これにより、**string**型の**EventName**という名前の**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスが作成されます。プロパティーは**EventToCommandBehavior**クラスが所有し、デフォルト値は**null**です。バインダブルプロパティの命名規則は、バインダブルプロパティ識別子が、**Create**メソッドで指定されたプロパティ名と一致し、 "Property"が追加されている必要があります。したがって、上記の例では、バインダブルプロパティ識別子は**EventNameProperty**です。

オプションで、**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスを作成するときに、次のパラメータを指定できます。

* バインドモード。これは、プロパティ値の変更が伝播する方向を指定するために使用されます。デフォルトのバインディングモードでは、変更が**source**から**target**に伝播します。
* プロパティ値が設定されたときに呼び出される検証デリゲート。詳細については、[バリデーションコールバック](#バリデーションコールバック)を参照してください。
* プロパティ値が変更されたときに呼び出されるデリゲートを変更するプロパティ。このデリゲートには、デリゲートを変更したプロパティと同じシグネチャがあります。
* プロパティ値が変更されたときに呼び出される強制値デリゲート。詳細については、[強制値コールバック](#強制値コールバック)を参照してください。
* デフォルトのプロパティ値を初期化するために使用される**Func**。詳細については、[Funcを使用したデフォルト値の作成](#funcを使用したデフォルト値の作成)を参照してください。

### アクセサの作成
バインダブルプロパティにアクセスするためにプロパティ構文を使用するには、プロパティアクセサが必要です。**Get**アクセサは、対応するバインド可能なプロパティに含まれる値を返す必要があります。これは、**[GetValue](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableObject.GetValue/p/Xamarin.Forms.BindableProperty/)**メソッドを呼び出して、値を取得するバインダブルプロパティ識別子を渡し、結果を必要な型にキャストすることで実現できます。**Set**アクセサは、対応するバインダブルプロパティの値を設定する必要があります。これは、**[SetValue](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableObject.SetValue/p/Xamarin.Forms.BindableProperty/System.Object/)**メソッドを呼び出し、値を設定するバインダブルプロパティ識別子と設定する値を渡すことで実現できます。

次のコード例は、**EventName**バインダブルプロパティのアクセサを示しています。

```csharp
public string EventName {
  get { return (string)GetValue (EventNameProperty); }
  set { SetValue (EventNameProperty, value); }
}
```

### バインダブルプロパティの使用
バインダブルプロパティが作成されると、XAMLまたはコードから使用される可能性があります。XAMLでは、プレフィックスを持つ名前空間を宣言し、CLR名前空間の名前を示す名前空間宣言と、オプションでアセンブリ名を指定することで実現します。詳細については、[XAML名前空間](#xaml名前空間)を参照してください。

次のコード例は、カスタム型を参照するアプリケーションコードと同じアセンブリ内で定義された、バインダブルプロパティを含むカスタム型のXAML名前空間を示しています。

```xml
<ContentPage ... xmlns:local="clr-namespace:EventToCommandBehavior" ...>
  ...
</ContentPage>
```

名前空間宣言は、次のXAMLコード例に示すように、**EventName**バインダブルプロパティを設定するときに使用されます。

```xml
<ListView ...>
  <ListView.Behaviors>
    <local:EventToCommandBehavior EventName="ItemSelected" ... />
  </ListView.Behaviors>
</ListView>
```

同等のC＃コードを次のコード例に示します。

```csharp
var listView = new ListView ();
listView.Behaviors.Add (new EventToCommandBehavior {
  EventName = "ItemSelected",
  ...
});
```

## [高度なシナリオ](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/#advanced)
**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスを作成するときに、高度なバインダブルプロパティシナリオを有効にするために設定できるオプションのパラメータがいくつかあります。このセクションでは、これらのシナリオについて説明します。

### プロパティの変更の検出
**[BindableProperty.Create](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドの**propertyChanged**パラメーターを指定することにより、静的なプロパティ変更のコールバックメソッドをバインダブルプロパティに登録できます。指定可能なコールバックメソッドは、バインダブルプロパティの値が変更されたときに呼び出されます。

次のコード例は、**EventName**バインダブルプロパティが**OnEventNameChanged**メソッドをプロパティ変更コールバックメソッドとして登録する方法を示しています。

```csharp
public static readonly BindableProperty EventNameProperty =
  BindableProperty.Create (
    "EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)
{
  // Property changed implementation goes here
}
```

property-changedコールバックメソッドでは、**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**パラメータは、所有しているクラスのどのインスタンスが変更を報告したかを示すために使用され、2つの**object**パラメータの値はバインド可能プロパティの古い値と新しい値を表します。

### [バリデーションコールバック](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/#validation)
**static**バリデーションコールバックメソッドは、**[BindableProperty.Create](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドの**validateValue**パラメーターを指定することによりバインダブルプロパティと一緒に登録できます。指定可能なコールバックメソッドは、バインダブルプロパティの値が設定されているときに呼び出されます。

次のコード例は、**Angle**のバインダブルプロパティがバリデーションコールバックメソッドとして**IsValidValue**メソッドを登録する方法を示しています。

```csharp
public static readonly BindableProperty AngleProperty =
  BindableProperty.Create ("Angle", typeof(double), typeof(HomePage), 0.0, validateValue: IsValidValue);
...

static bool IsValidValue (BindableObject view, object value)
{
  double result;
  bool isDouble = double.TryParse (value.ToString (), out result);
  return (result >= 0 && result <= 360);
}
```

バリデーションコールバックには値が与えられ、その値がプロパティに対して有効であれば**true**をそれ以外の場合には**false**を返します。バリデーションコールバックが**false**を返す場合、例外が発生します。これは開発者が処理する必要があります。バリデーションコールバックメソッドの典型的な使用法は、バインダブルプロパティが設定されているときに、int値またはdouble値に制約することです。たとえば、**IsValidValue**メソッドは、プロパティ値が0〜360の範囲内の**double**であることをチェックします。

### [強制値コールバック](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/#coerce)
**static**強制値コールバックメソッドは、**[BindableProperty.Create](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドの**coerceValue**パラメーターを指定することによって、バインダブルプロパティと一緒に登録できます。指定可能なコールバックメソッドは、バインダブルプロパティの値が変更されたときに呼び出されます。

強制値コールバックは、プロパティの値が変更されたときにバインダブルプロパティの再評価を強制するために使用されます。たとえば、強制値のコールバックを使用して、1つのバインダブルプロパティの値が別のバインダブルプロパティの値よりも大きくないようにすることができます。

次のコード例は、**Angle**のバインダブルプロパティが**CoerceAngle**メソッドを強制値コールバックメソッドとして登録する方法を示しています。

```csharp
public static readonly BindableProperty AngleProperty = BindableProperty.Create (
  "Angle", typeof(double), typeof(HomePage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty = BindableProperty.Create (
  "MaximumAngle", typeof(double), typeof(HomePage), 360.0);
...

static object CoerceAngle (BindableObject bindable, object value)
{
  var homePage = bindable as HomePage;
  double input = (double)value;

  if (input > homePage.MaximumAngle) {
    input = homePage.MaximumAngle;
  }

  return input;
}
```

**CoerceAngle**メソッドは**MaximumAngle**プロパティの値をチェックし、**Angle**プロパティの値がそれより大きい場合、値を**MaximumAngle**プロパティの値に強制します。

### [Funcを使用したデフォルト値の作成](https://developer.xamarin.com/guides/xamarin-forms/xaml/bindable-properties/#defaultfunc)
**Func**を使用すると、次のコード例に示すように、バインダブルプロパティのデフォルト値を初期化できます。

```csharp
public static readonly BindableProperty SizeProperty =
  BindableProperty.Create ("Size", typeof(double), typeof(HomePage), 0.0,
  defaultValueCreator: bindable => Device.GetNamedSize (NamedSize.Large, (Label)bindable));
```

**defaultValueCreator**パラメータは、**[Device.GetNamedSize](https://developer.xamarin.com/api/member/Xamarin.Forms.Device.GetNamedSize/p/Xamarin.Forms.NamedSize/System.Type/)**メソッドを呼び出す**Func**に設定され、ネイティブプラットフォームの**[Label](https://developer.xamarin.com/api/type/Xamarin.Forms.Label/)**で使用されるフォントの名前付きサイズを表す**double**を返します。

## まとめ
この記事では、バインダブルプロパティの概要を紹介し、バインダブルプロパティを作成、使用する方法を示しました。バインダブルプロパティは特殊なタイプのプロパティです。プロパティの値はXamarin.Formsプロパティシステムによって追跡されます。

# [添付プロパティ ](https://developer.xamarin.com/guides/xamarin-forms/xaml/attached-properties/)

**あらゆるオブジェクトで設定可能なグローバルプロパティの作成**

添付プロパティは、特殊型のバインダブルプロパティであり、1つのクラスで定義されていますが他のオブジェクトに関連付けられています。XAMLでは、クラスとプロパティ名がピリオドで区切られた属性として認識されます。この記事では、添付されたプロパティの概要を紹介し、それらを作成、使用する方法を示します。

## 概要
添付プロパティを使用すると、オブジェクトは自分のクラスで定義されていないプロパティの値を割り当てることができます。例えば、子要素は添付されたプロパティを使用して、親要素にそれらがどのようにユーザインターフェースに提示されるかを知らせることができます。**[Grid](https://developer.xamarin.com/api/type/Xamarin.Forms.Grid/)**コントロールを使用すると、**Grid.Row**と**Grid.Column**の添付プロパティを設定することで、子の行と列を指定できます。**Grid.Row**と**Grid.Column**は、**Grid**自体ではなく、**Grid**の子である要素に設定されているため、添付プロパティです。

バインダブルプロパティは、次のシナリオでは添付プロパティとして実装する必要があります。

* 定義クラス以外のクラスでプロパティ設定メカニズムを使用できるようにする必要があるとき。
* クラスが他のクラスと容易に統合される必要のあるサービスを表す場合。

バインダブルプロパティの詳細については、[バインダブルプロパティ](#バインダブルプロパティ)を参照してください。

## 添付プロパティの作成と使用
添付プロパティを作成するプロセスは次のとおりです。

1. **[CreateAttached](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.CreateAttached/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドオーバーロードのいずれかを使用して**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**インスタンスを作成します。
2. **static GetPropertyName**と**SetPropertyName**メソッドを、添付プロパティのアクセサとして提供します。

### プロパティの作成
他の型で使用するために添付プロパティを作成する場合、そのプロパティが作成されるクラスは**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**から派生する必要はありません。ただし、アクセサの**targer**プロパティは、**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**であるか、**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**派生する必要があります。

**[BindableProperty](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableProperty/)**型の**public static readonly**プロパティを宣言することによって、添付プロパティを作成できます。バインダブルプロパティは、**[BindableProperty.CreateAttached](https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.CreateAttached/p/System.String/System.Type/System.Type/System.Object/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate/Xamarin.Forms.BindableProperty+CoerceValueDelegate/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate/)**メソッドオーバーロードの1つの戻り値に設定する必要があります。宣言は所有クラスの本体内にある必要がありますが、メンバー定義の外にある必要があります。

次のコードは、添付プロパティの例を示しています。

```csharp
public static readonly BindableProperty HasShadowProperty =
  BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false);
```

これにより、**bool**型の**HasShadow**という名前の添付プロパティが作成されます。プロパティは**ShadowEffect**クラスが所有し、デフォルト値は**false**です。添付されたプロパティの命名規則は、添付されたプロパティ識別子が、**CreateAttached**メソッドで指定されたプロパティ名と "Property"が付加されたものとが一致しなければならないことです。したがって、上記の例では、添付プロパティ識別子は**HasShadowProperty**です。

作成時に指定できるパラメータを含む、バインダブルプロパティの作成の詳細については、**[バインダブルプロパティの作成と使用](#バインダブルプロパティの作成と使用)**を参照してください。

### アクセサの作成
静的な**GetPropertyName**と**SetPropertyName**メソッドは、添付プロパティのアクセサとして必要です。そうでない場合、プロパティシステムは添付プロパティを使用できなくなります。**GetPropertyName**アクセサは、次のシグネチャに準拠する必要があります。

```csharp
public static valueType GetPropertyName(BindableObject target)
```

**GetPropertyName**アクセサは、添付プロパティの対応する**BindableProperty**フィールドに含まれる値を返す必要があります。これは、**GetValue**メソッドを呼び出し、値を取得するバインダブルプロパティ識別子を渡し、結果の値を必要な型にキャストすることで実現できます。

**SetPropertyName**アクセサは、次のシグネチャに準拠する必要があります。

```csharp
public static void SetPropertyName(BindableObject target, valueType value)
```

**SetPropertyName**アクセサは、添付プロパティの対応する**BindableProperty**フィールドの値を設定する必要があります。これは、**SetValue**メソッドを呼び出し、値を設定するバインダブルプロパティ識別子と設定する値を渡すことで実現できます。

どちらのアクセサでも、**target**オブジェクトは**[BindableObject](https://developer.xamarin.com/api/type/Xamarin.Forms.BindableObject/)**であるか、**BindableObject**から派生している必要があります。

次のコード例は、**HasShadow**添付プロパティのアクセサを示しています。

```csharp
public static bool GetHasShadow (BindableObject view)
{
  return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)
{
  view.SetValue (HasShadowProperty, value);
}
```

### 添付プロパティの使用
添付されたプロパティが作成されると、XAMLまたはコードから使用される可能性があります。XAMLでは、プレフィックス付きの名前空間を宣言し、CLR（Common Language Runtime）名前空間名を示す名前空間宣言と、オプションでアセンブリ名を指定してこれを実現します。詳細については、[XAML名前空間](#xaml名前空間)を参照してください。

次のコード例は、カスタム型を参照するアプリケーションコードと同じアセンブリ内で定義された、関連付けられたプロパティを含むカスタム型のXAML名前空間を示しています。

```xml
<ContentPage ... xmlns:local="clr-namespace:EffectsDemo" ...>
  ...
</ContentPage>
```

XAMLの次のコード例に示すように、特定のコントロールの添付プロパティを設定するときに、名前空間宣言が使用されます。

```xml
<Label Text="Label Shadow Effect" local:ShadowEffect.HasShadow="true" />
```

同等のC＃コードを次のコード例に示します。

```csharp
var label = new Label { Text = "Label Shadow Effect" };
ShadowEffect.SetHasShadow (label, true);
```

### Style付きの添付プロパティの使用
添付プロパティは、スタイルによってコントロールに追加することもできます。次のXAMLコード例は、**[Label](https://developer.xamarin.com/api/type/Xamarin.Forms.Label/)**コントロールに適用できる、**HasShadow**添付プロパティを使用する*明示的な*スタイルを示しています。

```xml
<Style x:Key="ShadowEffectStyle" TargetType="Label">
  <Style.Setters>
    <Setter Property="local:ShadowEffect.HasShadow" Value="true" />
  </Style.Setters>
</Style>
```

**[Style](https://developer.xamarin.com/api/type/Xamarin.Forms.Style/)**は、次のコード例に示すように、**StaticResource**マークアップ拡張を使用して**Style**プロパティに**Style**インスタンスを設定することによって、**Label**に適用できます。

```xml
<Label Text="Label Shadow Effect" Style="{StaticResource ShadowEffectStyle}" />
```

スタイルの詳細については、[Style](https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/)を参照してください。

### 高度なシナリオ
添付プロパティを作成するときは、高度な添付プロパティのシナリオを有効にするために設定できるいくつかのオプションのパラメータがあります。これには、プロパティ変更の検出、プロパティ値の検証、プロパティ値の強制変換が含まれます。詳細については、[高度なシナリオ](#高度なシナリオ)を参照してください。

## まとめ
この記事では、添付プロパティの概要と、それらを作成、使用する方法を示しました。添付プロパティは、特別の種類のバインダブルプロパティです。クラス内で定義されていますが、他のオブジェクトに関連付けられています。XAMLでは、クラスとプロパティ名がピリオドで区切られた属性として認識されます。

# [リソースディクショナリー](https://developer.xamarin.com/guides/xamarin-forms/xaml/resource-dictionaries/)

**XAMLリソースの再利用**

XAMLリソースは、複数回使用できるオブジェクトの定義です。ResourceDictionaryを使用すると、リソースを単一の場所に定義し、Xamarin.Formsアプリケーション全体で再利用することができます。この記事では、ResourceDictionaryの作成と使用方法、マージする方法について説明します。

## 概要
**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**は、Xamarin.Formsアプリケーションで使用されるリソースのリポジトリです。**ResourceDictionary**に格納される一般的なリソースには、[style](https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/)、[control templates](https://developer.xamarin.com/guides/xamarin-forms/templates/control-templates/)、[data templates](https://developer.xamarin.com/guides/xamarin-forms/templates/data-templates/)、色、コンバータが含まれます。

XAMLでは、リソースは**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**で定義され、**StaticResource**マークアップ拡張を使用して取得され、要素に適用されます。C#では、リソースは**ResourceDictionary**で定義され、文字列ベースのインデクサを使用して取得され、要素に適用されます。しかし、**ResourceDictionary**からリソースを最初に取得することなく、ビジュアル要素のプロパティにリソースを簡単に割り当てることができるため、C#で**ResourceDictionary**を使用する利点はほとんどありません。

## ResourceDictionaryの作成と使用
リソースは、ページまたはコントロールの**[Resources](https://developer.xamarin.com/api/property/Xamarin.Forms.VisualElement.Resources/)**コレクション、またはアプリケーションの**[Resources](https://developer.xamarin.com/api/property/Xamarin.Forms.VisualElement.Resources/)**コレクションに添付された**ResourceDictionary**で定義できます。**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**を定義する場所を選択すると、使用できる場所に影響があります。

* コントロールレベルで定義された**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**のリソースは、コントロールとその子にのみ適用できます。
* ページレベルで定義された**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**内のリソースは、ページおよびその子にのみ適用できます。
* アプリケーションレベルで定義された
**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**のリソースは、アプリケーション全体に適用できます。

次のXAMLコード例は、アプリケーションレベルの**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**で定義されたリソースを示しています。

```xml
<Application ...>
    <Application.Resources>
        <ResourceDictionary>
            <Color x:Key="PageBackgroundColor">Yellow</Color>
            <Color x:Key="HeadingTextColor">Black</Color>
            <Color x:Key="NormalTextColor">Blue</Color>
            <Style x:Key="LabelPageHeadingStyle" TargetType="Label">
                <Setter Property="FontAttributes" Value="Bold" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>
```

この**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**は、3つの[Color](https://developer.xamarin.com/api/type/Xamarin.Forms.Color/)リソースと[Style](https://developer.xamarin.com/api/type/Xamarin.Forms.Style/)リソースを定義します。 XAML Appクラスの作成の詳細については、[App Class](https://developer.xamarin.com/guides/xamarin-forms/working-with/application-class/)を参照してください。

各リソースには**x:Key**属性を使用して指定されたキーがあり、**ResourceDictionary**で説明的なキーが与えられます。このキーは、コントロールレベル**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**
で定義された追加のリソースを示す次のXAMLコードの例に示すように、**StaticResource**マークアップ拡張によって**ResourceDictionary**からリソースを取得するために使用されます。

```xml
<StackLayout Margin="0,20,0,0">
  <StackLayout.Resources>
    <ResourceDictionary>
      <Style x:Key="LabelNormalStyle" TargetType="Label">
        <Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
      </Style>
      <Style x:Key="MediumBoldText" TargetType="Button">
        <Setter Property="FontSize" Value="Medium" />
        <Setter Property="FontAttributes" Value="Bold" />
      </Style>
    </ResourceDictionary>
  </StackLayout.Resources>
  <Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
    <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
           Margin="10,20,10,0"
           Style="{StaticResource LabelNormalStyle}" />
    <Button Text="Navigate"
            Clicked="OnNavigateButtonClicked"
            TextColor="{StaticResource NormalTextColor}"
            Margin="0,20,0,0"
            HorizontalOptions="Center"
            Style="{StaticResource MediumBoldText}" />
</StackLayout>
```

最初の**[Label](https://developer.xamarin.com/api/type/Xamarin.Forms.Label/)**インスタンスは、アプリケーションレベルの**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**
で定義されている**LabelPageHeadingStyle**リソースを取得および使用します。2番目の**Label**インスタンスは、コントロールレベル**ResourceDictionary**で定義された**LabelNormalStyle**リソースを取得して使用します。同様に、**[Button](https://developer.xamarin.com/api/type/Xamarin.Forms.Button/)**インスタンスは、アプリケーションレベルの**ResourceDictionary**で定義された**NormalTextColor**リソース、およびコントロールレベルの**ResourceDictionary**で定義された**MediumBoldText**リソースを取得および使用します。この結果、次のスクリーンショットが表示されます。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/resource-dictionaries/Images/screenshots-sml.png" title="Consuming ResourceDictionary Resources" alt="Consuming ResourceDictionary Resources" width="60%">

注意: 単一ページに固有のリソースは、アプリケーションレベルのリソースディクショナリーに含めてはいけません。そのようなリソースは、ページで必要とされるときではなく、アプリケーションの起動時に解析されるためです。詳細については、[アプリケーションリソースディクショナリーサイズを小さくする](https://developer.xamarin.com/guides/xamarin-forms/deployment,_testing,_and_metrics/performance/#Reduce_the_Application_Resource_Dictionary_Size)を参照してください。

## リソースの上書き
**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**リソースが**x:Key**属性値を共有する場合、ビュー階層の下位に定義されたリソースは、上位に定義されたリソースよりも優先されます。たとえば、アプリケーションレベルで**PageBackgroundColor**リソースを**Blue**に設定しても、ページレベルの**PageBackgroundColor**リソースが**Yellow**に設定されていると上書きされます。同様に、ページレベルの**PageBackgroundColor**リソースは、コントロールレベルの**PageBackgroundColor**リソースによってオーバーライドされます。

```xml
<ContentPage ... BackgroundColor="{StaticResource PageBackgroundColor}">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Color x:Key="PageBackgroundColor">Blue</Color>
            <Color x:Key="NormalTextColor">Yellow</Color>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Margin="0,20,0,0">
        ...
        <Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
        <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
               Margin="10,20,10,0"
               Style="{StaticResource LabelNormalStyle}" />
        <Button Text="Navigate"
                Clicked="OnNavigateButtonClicked"
                TextColor="{StaticResource NormalTextColor}"
                Margin="0,20,0,0"
                HorizontalOptions="Center"
                Style="{StaticResource MediumBoldText}" />
    </StackLayout>
</ContentPage>
```

アプリケーションレベルで定義された元の**PageBackgroundColor**および**NormalTextColor**インスタンスは、ページレベルで定義された**PageBackgroundColor**および**NormalTextColor**インスタンスによってオーバーライドされます。したがって、次のスクリーンショットに示すように、ページの背景色は青色になり、ページ上のテキストは黄色になります。

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/resource-dictionaries/Images/overridding-screenshots-sml.png" title="Overriding ResourceDictionary Resources" alt="Overriding ResourceDictionary Resources" width="60%">

ただし、**BarBackgroundColor**プロパティがアプリケーションレベルの**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**で定義された**[PageBackgroundColor](https://developer.xamarin.com/api/property/Xamarin.Forms.NavigationPage.BarBackgroundColor/)**リソースの値に設定されているため、**[NavigationPage](https://developer.xamarin.com/api/type/Xamarin.Forms.NavigationPage/)**のバックグラウンドバーはまだ黄色です。

## マージドリソースディクショナリー
マージドリソースディクショナリーは、1つ以上の**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**
インスタンスを別のインスタンスにマージします。これは、**ResourceDictionary.MergedDictionaries**プロパティを、アプリケーション、ページ、またはコントロールレベルにマージされる1つ以上の**ResourceDictionary**に設定することによって実行されます。

注意: **[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**型には、現在の**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**インスタンスにマージされる**MergedWith**プロパティの値として指定された**ResourceDictionary**を使用して、単一の**ResourceDictionary**を別の**ResourceDictionary**にマージするために使用できる**[MergedWith](https://developer.xamarin.com/api/property/Xamarin.Forms.ResourceDictionary.MergedWith/)**プロパティもあります。**MergedWith**プロパティを使用してマージすると、**x:Key**属性値を共有する現在の**ResourceDictionary**のすべてのリソースが、マージ対象の**ResourceDictionary**のリソースと置き換えられます。ただし、**MergedWith**プロパティはXamarin.Formsの今後のリリースで非推奨になります。したがって、**MergedDictionaries**プロパティを使用して**ResourceDictionary**インスタンスをマージすることをお勧めします。

次のXAMLコード例は、単一のリソースを含む**MyResourceDictionary**という名前の**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**を示しています。

```xml
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ResourceDictionaryDemo.MyResourceDictionary">
    <DataTemplate x:Key="PersonDataTemplate">
        <ViewCell>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.5*" />
                    <ColumnDefinition Width="0.2*" />
                    <ColumnDefinition Width="0.3*" />
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Name}" TextColor="{StaticResource NormalTextColor}" FontAttributes="Bold" />
                <Label Grid.Column="1" Text="{Binding Age}" TextColor="{StaticResource NormalTextColor}" />
                <Label Grid.Column="2" Text="{Binding Location}" TextColor="{StaticResource NormalTextColor}" HorizontalTextAlignment="End" />
            </Grid>
        </ViewCell>
    </DataTemplate>
</ResourceDictionary>
```

**MyResourceDictionary**は、任意のアプリケーション、ページ、またはコントロールレベルの**ResourceDictionary**にマージできます。次のXAMLコード例は、**MergedDictionaries**プロパティを使用して、ページレベルの**ResourceDictionary**にマージされていることを示しています。

```xml
<ContentPage ...>
    <ContentPage.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <local:MyResourceDictionary />
                <!-- Add more resource dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>
```

マージされた**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**リソースが同じ**x:Key**属性値を共有する場合、Xamarin.Formsは次のリソース優先順位を使用します。

1. リソースディクショナリーのローカルリソース
2. **[MergedWith](https://developer.xamarin.com/api/property/Xamarin.Forms.ResourceDictionary.MergedWith/)**プロパティを使用してマージされたリソースディクショナリーに含まれるリソース
3. **MergedDictionaries**コレクションを使用してマージされたリソースディクショナリーに含まれるリソースを、**MergedDictionaries**プロパティにリストされている順序で返します。

注意: アプリケーションに複数の大きなリソース辞書が含まれている場合、リソース辞書を検索することは計算集約的な作業になります。したがって、不要な検索を避けるために、アプリケーション内の各ページがそのページに適したリソース辞書のみを使用するようにしてください。

## まとめ
この記事では、**[ResourceDictionary](https://developer.xamarin.com/api/type/Xamarin.Forms.ResourceDictionary/)**を作成および使用する方法、リソースディクショナリーをマージする方法について説明しました。**ResourceDictionary**を使用すると、リソースを単一の場所に定義し、Xamarin.Formsアプリケーション全体で再利用することができます。

# [XAML Standard（プレビュー）](https://developer.xamarin.com/guides/xamarin-forms/xaml/standard/)

**Xamarin.FormsでXAML Standardプレビューを調べる方法**

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/standard/Images/preview.png" title="Preview" alt="Preview">

Xamarin.FormsでXAML Standardを試すには、次の手順に従ってください。

1. プレビューNuGetパッケージを[こちら](https://aka.ms/xf-xamlstandard-nuget)からダウンロードします。
2. **Xamarin.Forms.Alias** NuGetパッケージをXamarin.Forms PCL、.NET Standard、およびプラットフォームプロジェクトに追加します。
3. **Alias.Init()**でパッケージを初期化します。
4. **xmlns:a="clr-namespace:Xamarin.Forms.Alias;assembly=Xamarin.Forms.Alias"**を参照する**xmlns:a**を追加します。
5. XAMLの型を使用します。 - 詳細については、[コントロールリファレンス](#xaml-standardプレビューコントロール)を参照してください。

次のXAMLは、Xamarin.Forms **ContentPage**で使用されているXAML Standardコントロールの一部を示しています。

```xml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:a="clr-namespace:Xamarin.Forms.Alias;assembly=Xamarin.Forms.Alias"
    x:Class="XAMLStandardSample.ItemsPage" 
    Title="{Binding Title}" x:Name="BrowseItemsPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
    </ContentPage.ToolbarItems>
    <ContentPage.Content>
        <a:StackPanel>
            <ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Padding="10">
                                <a:TextBlock Text="{Binding Text}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemTextStyle}" FontSize="16" />
                                <a:TextBlock Text="{Binding Description}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemDetailTextStyle}" FontSize="13" />
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </a:StackPanel>
    </ContentPage.Content>
</ContentPage>
```

注意: XAML Standardコントロールのxmlns **a:**プレフィックスが必要なのは、現在のプレビューの制限事項です。

# [XAML Standard（プレビュー）コントロール](https://developer.xamarin.com/guides/xamarin-forms/xaml/standard/controls/)

**Xamarin.FormsでXAML Standardプレビューを調べる方法**

<img src="https://developer.xamarin.com/guides/xamarin-forms/xaml/standard/Images/preview.png" title="Preview" alt="Preview">

このページには、プレビューで使用できるXAML Standardコントロールと、同等のXamarin.Formsコントロールを一覧表示しています。
また、XAML Standardに新しいプロパティと列挙名を持つコントロールの一覧もあります。

## コントロール

| XAMARIN.FORMS | XAML STANDARD |
| :------------ | :------------ |
| Frame | Border |
| Picker | ComboBox |
| ActivityIndicator | ProgressRing |
| StackLayout | StackPanel |
| Label | TextBlock |
| Entry | TextBox |
| Switch | ToggleSwitch |
| ContentView | UserControl |

## プロパティと列挙型

| XAMARIN.FORMS<br>CONTROLS WITH UPDATED PROPERTIES | XAMARIN.FORMS<br>PROPERTY OR ENUM | XAML STANDARD<br>EQUIVALENT |
|:--|:--|:--|
| Button, Entry, Label, DatePicker, Editor, SearchBar, TimePicker | TextColor | Foreground |
| VisualElement | BackgroundColor | Background * |
| Picker, Button | BorderColor, OutlineColor | BorderBrush |
| Button | BorderWidth | BorderThickness |
| ProgressBar | Progress | Value |
| Button, Entry, Label, Editor, SearchBar, Span, Font | FontAttributes<br>Bold, Italic, None | FontStyle<br>Italic, Normal |
| Button, Entry, Label, Editor, SearchBar, Span, Font | FontAttributes | FontWeights * <br>Bold, Normal |
| InputView | Keyboard<br>Default, Url, Number, Telephone, Text, Chat, Email | InputScopeNameValue * <br>Default, Url, Number, TelephoneNumber, Text, Chat, EmailNameOrAddress |
| StackPanel | StackOrientation | Orientation * |

注意:　*が付いている項目は、現在のプレビューでは不完全です。