共用方式為


Xamarin.Mac 中的數據系結和索引鍵/值編碼

本文涵蓋使用索引鍵/值編碼和索引鍵/值觀察,以允許將數據系結至 Xcode 介面產生器中的 UI 元素。

概觀

在 Xamarin.Mac 應用程式中使用 C# 和 .NET 時,您可以存取開發人員在 和 XcodeObjective-C運作的相同機碼值編碼和數據系結技術。 由於 Xamarin.Mac 直接與 Xcode 整合,因此您可以使用 Xcode 的 介面產生器 將數據系結至 UI 元素,而不是撰寫程式代碼。

藉由在 Xamarin.Mac 應用程式中使用索引鍵/值編碼和數據系結技術,您可以大幅減少您必須撰寫和維護的程式碼數量,以填入和使用 UI 元素。 您也可以從前端使用者介面(Model-View-Controller)進一步分離備份數據(數據模型),進而更輕鬆地維護、更有彈性的應用程式設計。

執行中應用程式的範例

在本文中,我們將討論在 Xamarin.Mac 應用程式中使用索引鍵/值編碼和數據系結的基本概念。 強烈建議您先完成 Hello,Mac 文章,特別是 Xcode 和 Interface Builder 和 Outlets 和 Actions 簡介小節,因為它涵蓋我們將在本文中使用的重要概念和技術。

您可能也想要查看 Xamarin.Mac Internals 檔的公開 C# 類別/方法Objective-C一節,它也會說明 Register 用來將 C# 類別連線至Objective-C物件和 UI 元素的 和 Export 屬性。

什麼是索引鍵/值編碼

索引鍵/值編碼 (KVC) 是間接存取物件屬性的機制,使用索引鍵(特別格式化的字串)來識別屬性,而不是透過實例變數或存取子方法存取它們。get/set 藉由在 Xamarin.Mac 應用程式中實作索引鍵/值編碼相容存取子,您可以存取其他 macOS(先前稱為 OS X)功能,例如索引鍵/值觀察(KVO)、數據系結、Core Data、Cocoa 系結和可腳本性。

藉由在 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-Value Observed變更,存取子必須在和 DidChangeValue 方法呼叫中WillChangeValue包裝其值的變更(指定與 Export 屬性相同的Key)。 例如:

set {
    WillChangeValue ("Name");
    _name = value;
    DidChangeValue ("Name");
}

此步驟對於 Xcode 介面產生器中的數據系結非常重要 (如本文稍後所見)。

如需詳細資訊,請參閱Apple的 索引鍵/值編碼程序設計指南

索引鍵和金鑰路徑

Key 是識別物件特定屬性的字串。 一般而言,索引鍵會對應至索引鍵值編碼相容物件中存取子方法的名稱。 索引鍵必須使用 ASCII 編碼,通常以小寫字母開頭,而且不能包含空格符。 因此,假設上述範例是 Name 類別的NamePersonModel索引鍵值。 其公開的索引鍵和屬性名稱不一定相同,不過在大部分情況下都是。

索引 鍵路徑 是點分隔的索引鍵字串,用來指定要周游的物件屬性階層。 序列中第一個索引鍵的 屬性是相對於接收者,而每個後續索引鍵都會相對於上一個屬性的值進行評估。 同樣地,您可以使用點表示法來周遊物件及其 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 會傳回指定之 Key 的值(做為 ), NSString相對於接收要求的 KVC 類別實例。 例如,如果 Person 是上面定義的類別實例 PersonModel

// Read value
var name = Person.ValueForKey (new NSString("Name"));

這會傳回該 實例PersonModelName 屬性值。

使用機碼/值編碼設定值

同樣地,相對於 SetValueForKey 接收要求的 KVC 類別實例,設定指定之 Key (as 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的 索引鍵/值觀察程序設計指南簡介

資料繫結

下列各節將示範如何使用索引鍵/值編碼和索引鍵/值觀察相容類別,將數據系結至 Xcode 介面產生器中的 UI 元素,而不是使用 C# 程式代碼來讀取和寫入值。 如此一來,您就可以將數據模型與用來顯示它們的檢視區隔開,讓 Xamarin.Mac 應用程式更有彈性且更容易維護。 您也大幅減少必須撰寫的程式代碼數量。

定義您的數據模型

您必須先在 Xamarin.Mac 應用程式中定義 KVC/KVO 相容類別,才能在介面產生器中系結 UI 元素,才能做為 系結的數據模型 。 數據模型會提供使用者介面中顯示的所有數據,並在執行應用程式時,接收使用者對 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
    }
}

上述「什麼是索引鍵/值編碼」一節涵蓋此類別的大部分功能。 不過,讓我們看看一些特定元素和一些新增專案,讓這個類別可以做為陣列控制器和樹狀目錄控制器的數據模型(我們稍後將使用此專案將數據系結樹視圖、大綱檢視集合檢視)。

首先,因為員工可能是經理,所以我們已使用 NSArray (特別是 NSMutableArray ,以便修改值),以允許他們管理的員工附加至他們:

private NSMutableArray _people = new NSMutableArray();
...

[Export("personModelArray")]
public NSArray People {
    get { return _people; }
}

這裡要注意的兩件事:

  1. 我們使用 而不是NSMutableArray標準 C# 數位列或集合,因為這是數據系結至 AppKit 控件的需求,例如數據表檢視、大綱檢視集合
  2. 我們藉由將數據系結目的轉換成 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 元素的 Icon 中(在 KVO 期間):

[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");
    }
}

請注意,除了自己的 Key 之外,存取isManager子也會傳送 金鑰的 WillChangeValue IconDidChangeValue 訊息,因此也會看到變更。

我們將在本文的其餘部分使用 PersonModel 數據模型。

簡單資料繫結

定義數據模型后,讓我們看看 Xcode 介面產生器中的數據系結簡單範例。 例如,讓我們將表單新增至 Xamarin.Mac 應用程式,以用來編輯 PersonModel 我們上面定義的 。 我們將新增一些文字欄位和複選框,以顯示和編輯模型的屬性。

首先,讓我們在 Interface Builder 中將新的檢視控制器新增至 Main.storyboard 檔案,並將類別SimpleViewController命名為 :

使用名為 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 中編輯它。 將表單設定為如下所示:

在 Xcode 中編輯分鏡腳本

若要將數據系結至 PersonModel 透過密鑰公開的 Person 表單,請執行下列動作:

  1. 選取 [ 員工名稱 文字] 字段,然後切換至 [ 系結偵測器]。

  2. 核取 [ 系結至] 方塊,然後從下拉式清單中選取 [ 簡單檢視控制器 ]。 下一步輸入 self.Person.Name 金鑰 路徑

    輸入金鑰路徑的自我點人點名稱。

  3. 選取 [ 職業 文字欄位],然後核取 [ 系結至 ] 方塊,然後從下拉式清單中選取 [ 簡單檢視控制器 ]。 下一步輸入 self.Person.Occupation 金鑰 路徑

    輸入索引鍵路徑的自我點人員點職業。

  4. 選取 [ 員工是經理 ] 複選框,然後核取 [ 系結至 ] 方塊,然後從下拉式清單中選取 [ 簡單檢視控制器 ]。 下一步輸入 self.Person.isManager 金鑰 路徑

    輸入索引鍵路徑的自我點 Person 點是Manager。

  5. 選取 [ 員工管理 文字欄位數目],然後核取 [ 系結至 ] 方塊,然後從下拉式清單中選取 [ 簡單檢視控制器 ]。 下一步輸入 self.Person.NumberOfEmployees 金鑰 路徑

    輸入索引鍵路徑的自我點 Person 點 NumberOfEmployees。

  6. 如果員工不是經理,我們想要隱藏 [員工管理標籤數目] 和 [文字字段]。

  7. 選取 [ 員工管理 標籤數目],展開 [ 隱藏 ] 關閉,然後核取 [ 系結至 ] 方塊,然後從下拉式清單中選取 [ 簡單檢視控制器 ]。 下一步輸入 self.Person.isManager 金鑰 路徑

    輸入非管理員密鑰路徑的自我點 Person 點是Manager。

  8. 從[值轉換器] 下拉式清單中選取NSNegateBoolean

    選取 NSNegateBoolean 索引鍵轉換

  9. 這會告知數據系結,如果 屬性的值 isManagerfalse,標籤將會隱藏。

  10. 針對 [員工管理文字欄位數目] 重複步驟 7 和 8

  11. 儲存變更並返回 Visual Studio for Mac 以與 Xcode 同步。

如果您執行應用程式,來自 Person 屬性的值會自動填入我們的表單:

顯示自動填入的表單

使用者對表單所做的任何變更都會寫回檢視 Person 控制器中的屬性。 例如,取消選取 Employee 是經理 更新 Person 我們的 PersonModel 實例,並 自動隱藏 [員工管理 標籤和文字欄位數目] (透過資料系結):

隱藏非經理的員工數目

數據表檢視數據系結

現在,我們已經有數據系結的基本概念,讓我們看看更複雜的數據系結工作,方法是使用 數位控制器 和數據系結至數據表檢視。 如需使用數據表檢視的詳細資訊,請參閱我們的 數據表檢視 檔。

首先,讓我們在 Interface Builder 中將新的檢視控制器新增至 Main.storyboard 檔案,並將類別TableViewController命名為 :

使用名為 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讀取和寫入數據。

接下來,載入檢視時,我們需要使用下列程式代碼填入數位列器:

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 檔案以開啟它以在介面產生器中編輯。 配置數據表,看起來如下:

配置新的數據表檢視

我們需要新增 數位控制器 ,以將系結數據提供給數據表,請執行下列動作:

  1. 將數位控制器連結庫偵測器拖曳至介面編輯器

    從連結庫選取數位控制器

  2. 在 [介面階層] 中選取 [陣列控制器],然後切換至 [屬性偵測器]:

    選取屬性偵測器

  3. 針對 [類別名稱] 輸入 PersonModel ,按兩下 [加號] 按鈕並新增三個 [金鑰]。 將它們 Name命名為、 OccupationisManager

    將必要的金鑰路徑新增至物件控制器。

  4. 這會告訴數位控制器它正在管理的數位,以及它應該公開哪些屬性(透過密鑰)。

  5. 切換至系結偵測器,然後在 [內容陣列] 下選取 [系結至] 和 [數據表檢視控制器]。 輸入的self.personModelArray模型金鑰路徑

    輸入金鑰路徑

  6. 這會將數位控制器系結至我們在檢視控制器上公開的 PersonModels 陣列。

現在我們需要將數據表檢視係結至數位控制器,請執行下列動作:

  1. 選取資料表檢視和系 結偵測器

    選取數據表檢視和系結偵測器。

  2. 在 [數據表內容] 關閉下,選取 [系結至] 和 [陣列控制器]。 輸入 arrangedObjects [ 控制器金鑰 ] 欄位:

    定義控制器金鑰

  3. 選取 [員工] 數據行底下的 [數據表檢視單元格]。 在 [值] 關閉下的 [系結檢查] 中,選取 [系結至][數據表數據格檢視]。 輸入 objectValue.Name 模型 索引鍵路徑

    設定 Employee 資料行的模型索引鍵路徑。

  4. objectValue 是陣列中由陣列控制器管理的目前 PersonModel

  5. 選取 [職業] 數據行底下的 [數據表檢視單元格]。 在 [值] 關閉下的 [系結檢查] 中,選取 [系結至][數據表數據格檢視]。 輸入 objectValue.Occupation 模型 索引鍵路徑

    設定職業數據行的模型索引鍵路徑。

  6. 儲存變更並返回 Visual Studio for Mac 以與 Xcode 同步。

如果我們執行應用程式,資料表將會填入的陣列 PersonModels

執行應用程式,以填入 PersonModel 的陣列。

大綱檢視數據系結

針對大綱檢視的數據系結與數據表檢視的系結非常類似。 主要差異在於,我們將使用樹狀控制器,而不是數位控制器,將系結的數據提供給大綱檢視。 如需使用大綱檢視的詳細資訊,請參閱大綱 檢視 檔。

首先,讓我們在 Interface Builder 中將新的檢視控制器新增至 Main.storyboard 檔案,並將類別OutlineViewController命名為 :

使用名為 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讀取和寫入數據。

接下來,載入檢視時,我們需要使用下列程式代碼填入數位列器:

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 檔案,以開啟它以在介面產生器中編輯。 配置數據表,看起來如下:

建立大綱檢視

我們需要新增 樹狀控制器 ,以提供系結數據至大綱,請執行下列動作:

  1. 將樹狀結構控制器連結庫偵測器拖曳至介面編輯器

    從連結庫選取樹狀控制器

  2. 選取 [介面階層] 中的 [樹狀控制器],然後切換至 [屬性偵測器]:

    選取屬性偵測器

  3. 針對 [類別名稱] 輸入 PersonModel ,按兩下 [加號] 按鈕並新增三個 [金鑰]。 將它們 Name命名為、 OccupationisManager

    新增 PersonModel 的必要金鑰路徑。

  4. 這會告訴樹狀目錄控制器其管理數位,以及它應該公開的屬性(透過索引鍵)。

  5. 在 [樹狀控制器] 區段的 [子系] 下輸入 ,在 [計數] 下輸入 personModelArray NumberOfEmployees ,然後在 [分葉] 底下輸入 :isEmployee

    設定樹狀控制器金鑰路徑

  6. 這會告訴樹狀目錄控制器在哪裡尋找任何子節點、有多少子節點,以及目前節點是否有子節點。

  7. 切換至 [系結偵測器],然後在 [內容陣列] 下選取 [系結至] 和 [檔案擁有者]。 輸入的self.personModelArray模型金鑰路徑

    編輯金鑰路徑

  8. 這會將樹狀目錄控制器系結至我們在檢視控制器上公開的 PersonModels 陣列。

現在我們需要將大綱檢視系結至樹狀控制器,請執行下列動作:

  1. 選取 [大綱檢視],然後在 [系結檢查]選取 :

    選取大綱檢視和系結偵測器。

  2. 在 [ 大綱檢視內容 ] 關閉下,選取 [ 系結至][樹狀目錄控制器]。 輸入 arrangedObjects [ 控制器金鑰 ] 欄位:

    設定控制器金鑰

  3. 選取 [員工] 數據行底下的 [數據表檢視單元格]。 在 [值] 關閉下的 [系結檢查] 中,選取 [系結至][數據表數據格檢視]。 輸入 objectValue.Name 模型 索引鍵路徑

    輸入模型索引鍵路徑值 objectValue 點名稱。

  4. objectValue 是樹狀結構控制器所管理陣列中的目前 PersonModel

  5. 選取 [職業] 數據行底下的 [數據表檢視單元格]。 在 [值] 關閉下的 [系結檢查] 中,選取 [系結至][數據表數據格檢視]。 輸入 objectValue.Occupation 模型 索引鍵路徑

    輸入模型索引鍵路徑值 objectValue dot Occupation。

  6. 儲存變更並返回 Visual Studio for Mac 以與 Xcode 同步。

如果我們執行應用程式,大綱將會填入我們的陣列 PersonModels

執行應用程式,以填入 PersonModel 的陣列。

集合檢視數據系結

與集合檢視的數據系結與數據表檢視非常類似,因為數位控制器用來提供集合的數據。 由於集合檢視沒有預設的顯示格式,因此需要更多工作才能提供使用者互動意見反應,以及追蹤用戶選取專案。

重要

由於 Xcode 7 和 macOS 10.11 (及更新版本的)問題,集合檢視無法在分鏡腳本 (.storyboard) 檔案內使用。 因此,您必須繼續使用 .xib 檔案來定義 Xamarin.Mac 應用程式的集合檢視。 如需詳細資訊,請參閱我們的 集合檢視 檔。

偵錯原生當機

在數據系結中犯錯可能會導致 Unmanaged 程式代碼中的原生損毀 ,並導致 Xamarin.Mac 應用程式完全失敗併發生 SIGABRT 錯誤:

原生當機對話框的範例

在數據系結期間,原生當機通常有四個主要原因:

  1. 您的數據模型不會繼承自 NSObject 或的 NSObject子類別。
  2. 您未使用 [Export("key-name")] 屬性公開Objective-C屬性。
  3. 您在 和 DidChangeValue 方法呼叫中WillChangeValue未包裝存取子值的變更(指定與 Export 屬性相同的索引鍵)。
  4. 您在介面產生器中的 系結偵測器 中有錯誤或錯誤的索引鍵。

譯碼當機

讓我們在數據系結中造成原生損毀,以便示範如何找出並修正它。 在介面產生器中,讓我們將集合檢視範例中第一個標籤的系結從 Name 變更為 Title

編輯系結鍵

讓我們儲存變更,切換回 Visual Studio for Mac 以與 Xcode 同步並執行應用程式。 顯示集合檢視時,應用程式會暫時當機並SIGABRT出現錯誤(如 Visual Studio for Mac 中的應用程式輸出所示),因為 PersonModel 不會公開具有 Key Title的屬性:

系結錯誤的範例

如果我們捲動至應用程式輸出錯誤頂端,我們可以看到解決問題的關鍵:

在錯誤記錄檔中尋找問題

這一行告訴我們,我們系結的對象上沒有索引鍵 Title 。 如果我們在 Interface Builder 中將系結變更回 Name ,請儲存、同步、重建並執行,應用程式將會如預期般執行,而不會發生問題。

摘要

本文已詳細探討在 Xamarin.Mac 應用程式中使用數據系結和索引鍵/值編碼。 首先,它會使用索引鍵/值編碼 (KVC) 和索引鍵/值觀察 (KVO) 將 C# 類別公開至 Objective-C 。 接下來,它示範如何使用 KVO 相容類別,並將它系結至 Xcode 介面產生器中的 UI 元素。 最後,它會顯示使用 數位控制器樹狀目錄控制器的複雜數據系結。