Xamarin.Mac でのデータ バインディングとキー値のコーディング
この記事では、Xcode の Interface Builder で UI 要素へのデータ バインディングを可能にするために、キー値のコーディングとキー値の監視の使用について説明します。
概要
Xamarin.Mac アプリケーションで C# と .NET を使用する場合、開発者と Xcode が行うのと同じキー値コーディングとデータ バインディング手法にObjective-Cアクセスできます。 Xamarin.Mac は Xcode と直接統合されるため、コードを記述する代わりに、Xcode の インターフェイス ビルダー を使用して UI 要素を使用してデータ バインドを行うことができます。
Xamarin.Mac アプリケーションでキー値のコーディングとデータ バインディングの手法を使用すると、UI 要素を設定して操作するために必要なコードの量を大幅に減メインできます。 また、バッキング データ (データ モデル) をフロントエンド ユーザー インターフェイス (Model-View-Controller) からさらに切り離すことで、アプリケーション設計のメインメインしやすくなるという利点もあります。
この記事では、Xamarin.Mac アプリケーションでのキー値のコーディングとデータ バインディングの操作の基本について説明します。 この記事で使用する 主要な概念と手法については、まず Hello Mac の記事、特 に Xcode とインターフェイス ビルダー と アウトレットとアクション の概要に関するセクションを参照することを強くお勧めします。
Xamarin.Mac Internals ドキュメントの「C# クラス/メソッドを Xamarin.Mac Internals のセクションにObjective-C公開する」も参照してください。C# クラスObjective-Cをオブジェクトと UI 要素に結び付けるために使用される属性についてもExport
説明Register
しています。
キー値のコーディングとは
キー値コーディング (KVC) は、インスタンス変数またはアクセサー メソッド () を介してプロパティにアクセスするのではなく、キー (特別に書式設定された文字列) を使用してプロパティを識別して、オブジェクトのプロパティに間接的にアクセスするためのメカニズムですget/set
。 Xamarin.Mac アプリケーションでキー値コーディングに準拠したアクセサーを実装することで、キー値監視 (KVO)、データ バインディング、コア データ、Cocoa バインディング、スクリプト機能など、他の macOS (旧称 OS X) 機能にアクセスできます。
Xamarin.Mac アプリケーションでキー値のコーディングとデータ バインディングの手法を使用すると、UI 要素を設定して操作するために必要なコードの量を大幅に減メインできます。 また、バッキング データ (データ モデル) をフロントエンド ユーザー インターフェイス (Model-View-Controller) からさらに切り離すことで、アプリケーション設計のメインメインしやすくなるという利点もあります。
たとえば、KVC 準拠オブジェクトの次のクラス定義を見てみましょう。
using System;
using Foundation;
namespace MacDatabinding
{
[Register("PersonModel")]
public class PersonModel : NSObject
{
private string _name = "";
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
}
public PersonModel ()
{
}
}
}
最初に、この属性は [Register("PersonModel")]
クラスを登録し、それを Objective-C. 次に、クラスを NSObject
継承する (または継承元の NSObject
サブクラス) 必要があります。これにより、クラスに KVC 準拠を許可するいくつかの基本メソッドが追加されます。 次に、この属性は [Export("Name")]
プロパティを Name
公開し、後で KVC と KVO の手法を使用してプロパティにアクセスするために使用される Key 値を定義します。
最後に、プロパティの値に対する Key-Value Observed の変更を行うことができるようにするには、アクセサーは値の変更をラップして WillChangeValue
メソッド呼び出しを行う必要があります (属性と DidChangeValue
同じキー Export
を指定します)。 次に例を示します。
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
この手順は、 Xcode のインターフェイス ビルダーのデータ バインディングに非常 に重要です (この記事の後半で説明します)。
詳細については、Apple の キー値コーディング プログラミング ガイドを参照してください。
キーとキー パス
Key は、オブジェクトの特定のプロパティを識別する文字列です。 通常、キーは、キー値コーディングに準拠したオブジェクトのアクセサー メソッドの名前に対応します。 キーは ASCII エンコードを使用する必要があります。通常は小文字で始まり、空白を含めてはなりません。 したがって、上記の例では、Name
クラスのプロパティPersonModel
の Name
Key Value になります。 公開するキーとプロパティの名前は同じである必要はありませんが、ほとんどの場合は同じです。
キー パスは、走査するオブジェクト プロパティの階層を指定するために使用されるドット区切りのキーの文字列です。 シーケンス内の最初のキーのプロパティは受信側に対して相対的であり、後続の各キーは前のプロパティの値を基準にして評価されます。 同様に、ドット表記を使用して、C# クラス内のオブジェクトとそのプロパティを走査します。
たとえば、クラスを展開し、プロパティを PersonModel
追加 Child
した場合は、次のようになります。
using System;
using Foundation;
namespace MacDatabinding
{
[Register("PersonModel")]
public class PersonModel : NSObject
{
private string _name = "";
private PersonModel _child = new PersonModel();
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
}
[Export("Child")]
public PersonModel Child {
get { return _child; }
set {
WillChangeValue ("Child");
_child = value;
DidChangeValue ("Child");
}
}
public PersonModel ()
{
}
}
}
子の名前へのキー パスは、 self.Child.Name
(キー値の使用方法に基づいて) または単純 Child.Name
になります。
キーと値のコーディングを使用した値の取得
このメソッドは ValueForKey
、要求を受け取る KVC クラスのインスタンスを基準にして、指定された Key の値を (a NSString
として) 返します。 たとえば、上記で定義したクラスのインスタンスのPersonModel
場合Person
は、次のようになります。
// Read value
var name = Person.ValueForKey (new NSString("Name"));
これにより、そのインスタンスPersonModel
のプロパティのName
値が返されます。
キー値コーディングを使用した値の設定
同様に、要求を SetValueForKey
受信する KVC クラスのインスタンスを基準にして、指定したキーの値を (a NSString
として) 設定します。 ここでも、次に示すように、クラスのインスタンスを PersonModel
使用します。
// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));
プロパティの値を . に変更しますName
Jane Doe
。
値の変更の監視
キー値監視 (KVO) を使用すると、KVC 準拠クラスの特定のキーにオブザーバーをアタッチし、そのキーの値が変更されるたびに通知を受け取ることができます (KVC 手法を使用するか、C# コードで特定のプロパティに直接アクセスします)。 次に例を示します。
// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
// Inform caller of selection change
Console.WriteLine("New Name: {0}", Person.Name)
});
これで、Name
クラスのインスタンスのPerson
PersonModel
プロパティが変更されるたびに、新しい値がコンソールに書き出されます。
詳細については、Apple の キー値監視プログラミング ガイドの概要を参照してください。
データ バインディング
次のセクションでは、C# コードを使用して値を読み書きするのではなく、キー値コーディングとキー値監視準拠クラスを使用して Xcode の Interface Builder の UI 要素にデータをバインドする方法について説明します。 この方法では、データ モデルを表示に使用するビューから分離し、Xamarin.Mac アプリケーションの柔軟性とメイン容易にします。 また、記述する必要があるコードの量を大幅に減らします。
データ モデルの定義
インターフェイス ビルダーで UI 要素をデータ バインドする前に、バインドのデータ モデルとして機能するように、Xamarin.Mac アプリケーションで KVC/KVO 準拠クラスを定義しておく必要があります。 データ モデルは、ユーザー インターフェイスに表示されるすべてのデータを提供し、アプリケーションの実行中にユーザーが UI で行ったデータに対する変更を受け取ります。
たとえば、従業員のグループを管理するアプリケーションを作成する場合は、次のクラスを使用してデータ モデルを定義できます。
using System;
using Foundation;
using AppKit;
namespace MacDatabinding
{
[Register("PersonModel")]
public class PersonModel : NSObject
{
#region Private Variables
private string _name = "";
private string _occupation = "";
private bool _isManager = false;
private NSMutableArray _people = new NSMutableArray();
#endregion
#region Computed Properties
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
}
[Export("Occupation")]
public string Occupation {
get { return _occupation; }
set {
WillChangeValue ("Occupation");
_occupation = value;
DidChangeValue ("Occupation");
}
}
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
[Export("isEmployee")]
public bool isEmployee {
get { return (NumberOfEmployees == 0); }
}
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
[Export("NumberOfEmployees")]
public nint NumberOfEmployees {
get { return (nint)_people.Count; }
}
#endregion
#region Constructors
public PersonModel ()
{
}
public PersonModel (string name, string occupation)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
}
public PersonModel (string name, string occupation, bool manager)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
this.isManager = manager;
}
#endregion
#region Array Controller Methods
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
isManager = true;
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
#endregion
}
}
このクラスのほとんどの機能については、上記の「キーと値の コーディング 」セクションで説明しました。 ただし、このクラスを配列コントローラーとツリー コントローラーのデータ モデルとして機能させるために行われたいくつかの特定の要素といくつかの追加を見てみましょう (後でデータ バインド ツリー ビュー、アウトライン ビュー、コレクション ビューに使用します)。
まず、従業員がマネージャーになる可能性があるため、(具体的にはNSMutableArray
値を変更できるように) を使用NSArray
して、管理している従業員にアタッチできるようにします。
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
次の 2 つの点に注意してください。
- これは、テーブル ビュー、アウトライン ビュー、コレクションなどの AppKit コントロールへのデータ バインドの要件であるため、標準の C# 配列またはコレクションの代わりに使用
NSMutableArray
しました。 - データ バインディングの目的で配列を a
NSArray
にキャストして従業員の配列を公開し、その C# 形式の名前を、People
データ バインディングで想定personModelArray
される名前に {class_name}Array という形式に変更しました (最初の文字は小文字になっています)。
次に、配列コントローラーとツリー コントローラーをサポートするために、いくつかの特別な名前のパブリック メソッドを追加する必要があります。
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
isManager = true;
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
これにより、コントローラーは、表示されるデータを要求および変更できます。 上記で公開されている NSArray
のと同様に、これらは非常に具体的な名前付け規則を持っています (一般的な C# の名前付け規則とは異なります)。
addObject:
- 配列にオブジェクトを追加します。insertObject:in{class_name}ArrayAtIndex:
- クラスの名前を指定{class_name}
します。 このメソッドは、指定されたインデックス位置にある配列にオブジェクトを挿入します。removeObjectFrom{class_name}ArrayAtIndex:
- クラスの名前を指定{class_name}
します。 このメソッドは、指定されたインデックス位置にある配列内のオブジェクトを削除します。set{class_name}Array:
- クラスの名前を指定{class_name}
します。 この方法では、既存の持ち運びを新しいものに置き換えることができます。
これらのメソッドの内部では、配列 WillChangeValue
の変更と DidChangeValue
KVO 準拠のメッセージをラップしました。
最後に、プロパティは Icon
プロパティの isManager
値に依存するため、プロパティの isManager
変更がデータ バインド UI 要素 (KVO 中) に Icon
反映されない場合があります。
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
これを修正するには、次のコードを使用します。
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
アクセサーは、独自のキーに加えて、isManager
キーのメッセージもDidChangeValue
Icon
送信WillChangeValue
しているため、変更も表示されることに注意してください。
この記事の残りの部分では、 PersonModel
データ モデルを使用します。
単純データ バインディング
データ モデルが定義された状態で、Xcode の Interface Builder でのデータ バインディングの簡単な例を見てみましょう。 たとえば、上記で定義した編集に使用できるフォームを Xamarin.Mac アプリケーションに PersonModel
追加しましょう。 モデルのプロパティを表示および編集するためのテキスト フィールドとチェック ボックスをいくつか追加します。
まず、インターフェイス ビルダーの Main.storyboard ファイルに新しいビュー コントローラーを追加し、そのクラスSimpleViewController
に名前を付けます。
次に、Visual Studio for Mac に戻り、(プロジェクトに自動的に追加された) SimpleViewController.cs ファイルを編集し、フォームのPersonModel
データ バインディング先となるインスタンスを公開します。 次のコードを追加します。
private PersonModel _person = new PersonModel();
...
[Export("Person")]
public PersonModel Person {
get {return _person; }
set {
WillChangeValue ("Person");
_person = value;
DidChangeValue ("Person");
}
}
次に、ビューが読み込まれたら、次のインスタンスを作成し、次の PersonModel
コードを設定します。
public override void ViewDidLoad ()
{
base.AwakeFromNib ();
// Set a default person
var Craig = new PersonModel ("Craig Dunn", "Documentation Manager");
Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
Person = Craig;
}
フォームを作成し、Main.storyboard ファイルをダブルクリックして、Interface Builder で編集するために開く必要があります。 フォームを次のようにレイアウトします。
データキーを使用して公開したフォームに PersonModel
フォームを Person
バインドするには、次の操作を行います。
従業員名テキスト フィールドを選択し、Bindings Inspector に切り替えます。
[バインドする] ボックスをオンにし、ドロップダウンから [簡易ビュー コントローラー] を選択します。 次にキー パスを入力
self.Person.Name
します。[職業テキスト]フィールドを選択し、[バインド]ボックスをチェックし、ドロップダウンから[簡易ビューコントローラ]を選択します。 次にキー パスを入力
self.Person.Occupation
します。[Employee is a Manager]\(従業員がマネージャーである\) チェックボックスを選択し、[バインド]ボックスをチェックし、ドロップダウンから[簡易ビュー コントローラ]を選択します。 次にキー パスを入力
self.Person.isManager
します。[従業員数管理テキスト] フィールドを選択し、[バインド] ボックスをチェックし、ドロップダウンから [簡易ビュー コントローラー] を選択します。 次にキー パスを入力
self.Person.NumberOfEmployees
します。従業員がマネージャーでない場合は、[従業員数管理ラベル] フィールドと [テキスト] フィールドを非表示にします。
[従業員数管理ラベル] を選択し、[非表示] ターンダウンを展開し、[バインド] ボックスをチェックし、ドロップダウンから [簡易ビュー コントローラー] を選択します。 次にキー パスを入力
self.Person.isManager
します。[値トランスフォーマー] ドロップダウンから選択
NSNegateBoolean
します。これにより、プロパティ
false
の値が ゚ の場合、ラベルが非表示になることがデータ バインディングにisManager
通知されます。[従業員数] 管理テキスト フィールドに対して手順 7 と 8 を繰り返します。
変更を保存し、Visual Studio for Mac に戻って Xcode と同期します。
アプリケーションを実行すると、プロパティの値が Person
フォームに自動的に設定されます。
ユーザーがフォームに加える変更は、ビュー コントローラーの Person
プロパティに書き戻されます。 たとえば、従業員の選択を解除すると、マネージャーは Microsoft PersonModel
のインスタンスをPerson
更新し、[従業員数] 管理ラベルとテキスト フィールドは (データ バインディングを介して) 自動的に非表示になります。
テーブル ビューのデータ バインディング
データ バインディングの基本を理解したので、配列コントローラーとテーブル ビューへのデータ バインディングを使用して、より複雑なデータ バインディング タスクを見てみましょう。 テーブル ビューの操作の詳細については、テーブル ビューのドキュメントを参照してください。
まず、インターフェイス ビルダーの Main.storyboard ファイルに新しいビュー コントローラーを追加し、そのクラスTableViewController
に名前を付けます。
次に、TableViewController.cs ファイル (プロジェクトに自動的に追加されたファイル) を編集し、フォームのデータ バインディング先となるクラスのPersonModel
配列 (NSArray
) を公開します。 次のコードを追加します。
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
...
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
上記の「データ モデルのPersonModel
定義」セクションのクラスで行ったように、配列コントローラーがコレクションのPersonModels
データを読み書きできるように、特別に名前付きの 4 つのパブリック メソッドを公開しました。
次に、ビューが読み込まれるときに、配列に次のコードを設定する必要があります。
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Build list of employees
AddPerson (new PersonModel ("Craig Dunn", "Documentation Manager", true));
AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
AddPerson (new PersonModel ("Larry O'Brien", "API Documentation Manager", true));
AddPerson (new PersonModel ("Mike Norman", "API Documenter"));
}
次に、テーブル ビューを作成し、Main.storyboard ファイルをダブルクリックして、インターフェイス ビルダーで編集するために開く必要があります。 テーブルを次のようにレイアウトします。
バインドされたデータを テーブルに提供するには、配列コントローラー を追加する必要があります。次の操作を行います。
ライブラリ インスペクターからインターフェイス エディターに配列コントローラーをドラッグします。
インターフェイス階層で配列コントローラーを選択し、属性インスペクターに切り替えます。
クラス名を入力
PersonModel
し、[プラス] ボタンをクリックし、3 つのキーを追加します。 それらに名前を付け、Occupation
次の操作を行isManager
いますName
。これにより、配列コントローラーが配列を管理しているものと、それが公開する必要があるプロパティ (キーを使用) が示されます。
Bindings Inspector に切り替え、[コンテンツ配列] で [バインド先] と [テーブル ビュー コントローラー] を選択します。 次の モデル キー パス を
self.personModelArray
入力します。これにより、配列コントローラーがビュー コントローラーで公開された配列
PersonModels
に結び付けられます。
次に、テーブル ビューを配列コントローラーにバインドする必要があります。次の操作を行います。
テーブル ビューとバインド インスペクターを選択します。
[テーブル コンテンツ] ターンダウンで、[バインド先] と [配列コントローラー] を選択します。 [コントローラー キー] フィールドに次のように入力
arrangedObjects
します。[従業員] 列の下にある [テーブル ビュー] セルを選択します。 [バインド]インスペクタの[値]ターンダウンで、[バインド先]と[テーブルセルビュー]を選択します。 [モデル キー パス] に入力
objectValue.Name
します。objectValue
は、配列コントローラーによって管理されている配列内の現在PersonModel
の値です。[職業] 列の [テーブル ビュー] セルを選択します。 [バインド]インスペクタの[値]ターンダウンで、[バインド先]と[テーブルセルビュー]を選択します。 [モデル キー パス] に入力
objectValue.Occupation
します。変更を保存し、Visual Studio for Mac に戻って Xcode と同期します。
アプリケーションを実行すると、テーブルに次の PersonModels
配列が設定されます。
アウトライン ビューのデータ バインディング
アウトライン ビューに対するデータ バインディングは、テーブル ビューに対するバインドとよく似ています。 主な違いは、配列コントローラーの代わりにツリー コントローラーを使用して、アウトライン ビューにバインドされたデータを提供することです。 アウトライン ビューの操作の詳細については、アウトライン ビューのドキュメントを参照してください。
まず、インターフェイス ビルダーの Main.storyboard ファイルに新しいビュー コントローラーを追加し、そのクラスOutlineViewController
に名前を付けます。
次に、OutlineViewController.cs ファイル (プロジェクトに自動的に追加されたファイル) を編集し、フォームのデータ バインディング先となるクラスのPersonModel
配列 (NSArray
) を公開します。 次のコードを追加します。
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
...
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
上記の「データ モデルのPersonModel
定義」セクションのクラスで行ったように、ツリー コントローラーとデータのコレクションPersonModels
からのデータの読み取りと書き込みを行えるように、特別に名前が付けられた 4 つのパブリック メソッドを公開しました。
次に、ビューが読み込まれるときに、配列に次のコードを設定する必要があります。
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Build list of employees
var Craig = new PersonModel ("Craig Dunn", "Documentation Manager");
Craig.AddPerson (new PersonModel ("Amy Burns", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Joel Martinez", "Web & Infrastructure"));
Craig.AddPerson (new PersonModel ("Kevin Mullins", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Mark McLemore", "Technical Writer"));
Craig.AddPerson (new PersonModel ("Tom Opgenorth", "Technical Writer"));
AddPerson (Craig);
var Larry = new PersonModel ("Larry O'Brien", "API Documentation Manager");
Larry.AddPerson (new PersonModel ("Mike Norman", "API Documenter"));
AddPerson (Larry);
}
次に、アウトライン ビューを作成し、Main.storyboard ファイルをダブルクリックして、インターフェイス ビルダーで編集するために開く必要があります。 テーブルを次のようにレイアウトします。
アウトラインにバインドされたデータを 提供するには、ツリー コントローラー を追加する必要があります。次の操作を行います。
ライブラリ インスペクターからインターフェイス エディターにツリー コントローラーをドラッグします。
インターフェイス階層でツリー コントローラを選択し、属性インスペクターに切り替えます。
クラス名を入力
PersonModel
し、[プラス] ボタンをクリックし、3 つのキーを追加します。 それらに名前を付け、Occupation
次の操作を行isManager
いますName
。これにより、ツリー コントローラーに対して、配列の管理内容と、(キーを介して) 公開する必要があるプロパティが示されます。
[ツリー コントローラ]セクションで、「子」と入力
personModelArray
し、[カウント]に「リーフ」と入力NumberOfEmployees
isEmployee
します。これにより、ツリー コントローラーは、子ノードを検索する場所、子ノードの数、および現在のノードに子ノードがあるかどうかを示します。
Bindings Inspector に切り替え、[コンテンツ配列] で [バインド先] と [ファイルの所有者] を選択します。 次の モデル キー パス を
self.personModelArray
入力します。これにより、ツリー コントローラーがビュー コントローラーで公開された配列
PersonModels
に結び付けられます。
次に、アウトライン ビューをツリー コントローラーにバインドする必要があります。次の操作を行います。
アウトラインビューを選択し、バインドインスペクターで以下を選択します。
[アウトライン ビュー コンテンツ]ターンダウンで、[バインド]、[ツリー コントローラー]の順に選択します。 [コントローラー キー] フィールドに次のように入力
arrangedObjects
します。[従業員] 列の下にある [テーブル ビュー] セルを選択します。 [バインド]インスペクタの[値]ターンダウンで、[バインド先]と[テーブルセルビュー]を選択します。 [モデル キー パス] に入力
objectValue.Name
します。objectValue
は、ツリー コントローラーによって管理されている配列内の現在PersonModel
の値です。[職業] 列の [テーブル ビュー] セルを選択します。 [バインド]インスペクタの[値]ターンダウンで、[バインド先]と[テーブルセルビュー]を選択します。 [モデル キー パス] に入力
objectValue.Occupation
します。変更を保存し、Visual Studio for Mac に戻って Xcode と同期します。
アプリケーションを実行すると、アウトラインに次の PersonModels
配列が設定されます。
コレクション ビューのデータ バインディング
コレクション ビューを使用したデータ バインディングは、配列コントローラーを使用してコレクションのデータを提供するため、テーブル ビューとのバインドとよく似ています。 コレクション ビューには既定の表示形式がないため、ユーザーの操作に関するフィードバックを提供し、ユーザーの選択を追跡するために、さらに多くの作業が必要です。
重要
Xcode 7 および macOS 10.11 (以降) の問題により、ストーリーボード (.storyboard) ファイル内でコレクション ビューを使用できません。 その結果、Xamarin.Mac アプリのコレクション ビューを定義するには、引き続き .xib ファイルを使用する必要があります。 詳細については、 コレクション ビュー のドキュメントを参照してください。
ネイティブ クラッシュのデバッグ
データ バインディングを間違えた場合 、アンマネージ コードで Native Crash が発生 し、Xamarin.Mac アプリケーションがエラーで SIGABRT
完全に失敗する可能性があります。
通常、データ バインディング中のネイティブ クラッシュの主な原因は 4 つあります。
- データ モデルの継承元
NSObject
またはサブクラスNSObject
ではありません。 - プロパティを属性の使用
[Export("key-name")]
にObjective-C公開しませんでした。 - アクセサーの値
WillChangeValue
とメソッド呼び出しに対する変更をラップしませんでした (属性とDidChangeValue
同じキーをExport
指定します)。 - インターフェイス ビルダーのバインド インスペクターでキーの入力が間違っているか間違っています。
クラッシュのデコード
データ バインディングを見つけて修正する方法を示すことができるように、データ バインディングでネイティブ クラッシュを引き起こしましょう。 インターフェイス ビルダーで、コレクション ビューの例 Name
の最初のラベルのバインドを次に Title
変更します。
変更を保存し、Visual Studio for Mac に戻って Xcode と同期し、アプリケーションを実行しましょう。 コレクション ビューが表示されると、キーTitle
を持つSIGABRT
プロパティが公開されないため、アプリケーションは一時的にエラー (Visual Studio for Mac のアプリケーション出力に示されているように) PersonModel
でクラッシュします。
アプリケーション出力のエラーの一番上までスクロールすると、問題を解決するための鍵が表示されます。
この行は、バインドするオブジェクトにキー Title
が存在しないことを示しています。 バインドを Interface Builder に戻し Name
、保存、同期、リビルド、実行すると、アプリケーションは問題なく正常に実行されます。
まとめ
この記事では、Xamarin.Mac アプリケーションでのデータ バインディングとキー値のコーディングの操作について詳しく説明しました。 最初に、キー値コーディング (KVC) とキー値監視 (KVO) を使用して C# クラス Objective-C を公開する方法について説明しました。 次に、KVO 準拠クラスを使用し、Xcode のインターフェイス ビルダーの UI 要素にデータ バインドする方法を示しました。 最後に、配列コントローラーとツリー コントローラーを使用した複雑なデータ バインディングを示しました。