Udostępnij za pośrednictwem


Powiązanie danych i kodowanie klucz-wartość na platformie Xamarin.Mac

W tym artykule opisano używanie kodowania klucz-wartość i obserwowania wartości klucza w celu umożliwienia powiązania danych z elementami interfejsu użytkownika w narzędziu Interface Builder programu Xcode.

Omówienie

Podczas pracy z językami C# i .NET w aplikacji platformy Xamarin.Mac masz dostęp do tych samych technik kodowania klucz-wartość i powiązania danych, które wykonuje deweloper pracujący w Objective-C środowisku Xcode. Ponieważ platforma Xamarin.Mac integruje się bezpośrednio z programem Xcode, możesz użyć narzędzia Interface Builder Xcode do powiązania danych z elementami interfejsu użytkownika zamiast pisania kodu.

Korzystając z technik kodowania klucz-wartość i powiązania danych w aplikacji Xamarin.Mac, możesz znacznie zmniejszyć ilość kodu, który trzeba napisać i obsługiwać, aby wypełnić elementy interfejsu użytkownika i pracować z elementami interfejsu użytkownika. Masz również korzyść z dalszego oddzielenia danych zapasowych (modelu danych) od interfejsu użytkownika frontonu (Model-View-Controller), co prowadzi do łatwiejszego utrzymania, bardziej elastycznego projektowania aplikacji.

Przykład uruchomionej aplikacji

W tym artykule omówimy podstawy pracy z kodowaniem klucz-wartość i powiązaniem danych w aplikacji platformy Xamarin.Mac. Zdecydowanie zaleca się, aby najpierw zapoznać się z artykułem Hello, Mac , w szczególności wprowadzenie do narzędzi Xcode i Interface Builder i Outlet and Actions , ponieważ obejmuje ona kluczowe pojęcia i techniki, których będziemy używać w tym artykule.

Warto zapoznać się z sekcją Uwidacznianie klas/metod Objective-C języka C# w sekcji dokumentu Xamarin.Mac Internals , a także objaśnienie Register atrybutów i Export używanych do podłączania klas języka C# do Objective-C obiektów i elementów interfejsu użytkownika.

Co to jest kodowanie klucz-wartość

Kodowanie klucz-wartość (KVC) jest mechanizmem uzyskiwania dostępu do właściwości obiektu pośrednio przy użyciu kluczy (specjalnie sformatowanych ciągów) do identyfikowania właściwości zamiast uzyskiwania do nich dostępu za pośrednictwem zmiennych wystąpienia lub metod dostępu (get/set). Implementując zgodne metody kodowania klucz-wartość w aplikacji Xamarin.Mac, uzyskujesz dostęp do innych funkcji systemu macOS (wcześniej znanych jako OS X), takich jak obserwowanie wartości klucza (KVO), powiązanie danych, dane podstawowe, powiązania cocoa i możliwość tworzenia skryptów.

Korzystając z technik kodowania klucz-wartość i powiązania danych w aplikacji Xamarin.Mac, możesz znacznie zmniejszyć ilość kodu, który trzeba napisać i obsługiwać, aby wypełnić elementy interfejsu użytkownika i pracować z elementami interfejsu użytkownika. Masz również korzyść z dalszego oddzielenia danych zapasowych (modelu danych) od interfejsu użytkownika frontonu (Model-View-Controller), co prowadzi do łatwiejszego utrzymania, bardziej elastycznego projektowania aplikacji.

Przyjrzyjmy się na przykład następującej definicji klasy obiektu zgodnego z 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")] Najpierw atrybut rejestruje klasę i uwidacznia ją w pliku Objective-C. Następnie klasa musi dziedziczyć z NSObject (lub podklasy dziedziczonej z NSObject), spowoduje to dodanie kilku metod bazowych, które umożliwiają klasę zgodności KVC. Następnie atrybut uwidacznia Name właściwość i definiuje wartość Klucza, [Export("Name")] która będzie później używana do uzyskiwania dostępu do właściwości za pośrednictwem technik KVC i KVO.

Na koniec, aby można było zmienić wartość klucza obserwowanego na wartość właściwości, metoda dostępu musi opakowować zmiany w jego wartości w WillChangeValue wywołaniach metody i DidChangeValue (określając ten sam klucz co Export atrybut). Na przykład:

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

Ten krok jest bardzo ważny w przypadku powiązania danych w narzędziu Interface Builder programu Xcode (jak zobaczymy w dalszej części tego artykułu).

Aby uzyskać więcej informacji, zobacz Przewodnik programowania kodowania klucz-wartość firmy Apple.

Klucze i ścieżki kluczy

Klucz to ciąg, który identyfikuje określoną właściwość obiektu. Zazwyczaj klucz odpowiada nazwie metody dostępu w obiekcie zgodnym z kodowaniem klucz-wartość. Klucze muszą używać kodowania ASCII, zwykle zaczyna się od małej litery i mogą nie zawierać białych znaków. W związku z tym, biorąc pod uwagę powyższy przykład, Name byłaby wartością Name klucza właściwości PersonModel klasy. Klucz i nazwa właściwości, którą uwidaczniają, nie muszą być takie same, jednak w większości przypadków są.

Ścieżka klucza to ciąg kluczy rozdzielonych kropkami używany do określania hierarchii właściwości obiektu do przechodzenia. Właściwość pierwszego klucza w sekwencji jest względna względem odbiornika, a każdy kolejny klucz jest oceniany względem wartości poprzedniej właściwości. W ten sam sposób używasz notacji kropkowej do przechodzenia przez obiekt i jego właściwości w klasie C#.

Jeśli na przykład rozszerzono klasę PersonModel i dodano Child właściwość:

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 ()
        {
        }
    }
}

Ścieżka klucza do nazwy elementu podrzędnego to self.Child.Name lub po prostu Child.Name (na podstawie sposobu użycia wartości klucza).

Pobieranie wartości przy użyciu kodowania klucz-wartość

Metoda ValueForKey zwraca wartość określonego klucza (jako NSString), względem wystąpienia klasy KVC odbierającego żądanie. Jeśli na przykład Person jest wystąpieniem klasy zdefiniowanej PersonModel powyżej:

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

Spowoduje to zwrócenie wartości Name właściwości dla tego wystąpienia klasy PersonModel.

Ustawianie wartości przy użyciu kodowania klucz-wartość

SetValueForKey Podobnie ustaw wartość określonego klucza (jako NSString), względem wystąpienia klasy KVC odbierającego żądanie. Ponownie, używając wystąpienia PersonModel klasy, jak pokazano poniżej:

// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));

Spowoduje zmianę wartości Name właściwości na Jane Doe.

Obserwowanie zmian wartości

Korzystając z funkcji obserwowania wartości klucza (KVO), można dołączyć obserwatora do określonego klucza zgodnej klasy KVC i otrzymywać powiadomienia o każdej zmianie wartości dla tego klucza (przy użyciu technik KVC lub bezpośredniego uzyskiwania dostępu do danej właściwości w kodzie języka C#). Na przykład:

// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
    // Inform caller of selection change
    Console.WriteLine("New Name: {0}", Person.Name)
});

Teraz za każdym razem, gdy Name właściwość Person wystąpienia PersonModel klasy zostanie zmodyfikowana, nowa wartość zostanie zapisana w konsoli.

Aby uzyskać więcej informacji, zobacz Wprowadzenie firmy Apple do podręcznika programowania z obserwacją wartości klucz-wartość.

Powiązanie danych

W poniższych sekcjach pokazano, jak można używać kodowania klucz-wartość i wartości klucz-wartość obserwowania zgodnej klasy w celu powiązania danych z elementami interfejsu użytkownika w konstruktorze interfejsu Xcode, zamiast odczytywać i zapisywać wartości przy użyciu kodu języka C#. W ten sposób oddzielisz model danych od widoków używanych do ich wyświetlania, dzięki czemu aplikacja Xamarin.Mac będzie bardziej elastyczna i łatwiejsza w obsłudze. Znacznie zmniejszasz również ilość kodu, który musi być napisany.

Definiowanie modelu danych

Aby można było powiązać element interfejsu użytkownika w narzędziu Interface Builder, musisz mieć klasę zgodną z KVC/KVO zdefiniowaną w aplikacji Xamarin.Mac, aby działać jako model danych dla powiązania. Model danych udostępnia wszystkie dane, które będą wyświetlane w interfejsie użytkownika i odbiera wszelkie modyfikacje danych, które użytkownik wprowadza w interfejsie użytkownika podczas uruchamiania aplikacji.

Jeśli na przykład tworzysz aplikację zarządzającą grupą pracowników, możesz użyć następującej klasy do zdefiniowania modelu danych:

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
    }
}

Większość funkcji tej klasy została omówiona w sekcji Co to jest kodowanie klucz-wartość powyżej. Przyjrzyjmy się jednak kilku konkretnym elementom i dodaniu, które zostały wprowadzone, aby umożliwić tej klasie działanie jako model danych dla kontrolerów tablicy i kontrolerów drzewa (które będziemy później używać do tworzenia powiązań widoków drzewa, widoków konspektu i widoków kolekcji).

Po pierwsze, ponieważ pracownik może być menedżerem, użyliśmy NSArray elementu (w szczególności NSMutableArray wartości, dzięki czemu można modyfikować wartości), aby umożliwić pracownikom, którym udało się dołączyć do nich:

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

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

W tym miejscu należy zwrócić uwagę na dwie kwestie:

  1. Użyliśmy NSMutableArray elementu zamiast standardowej tablicy lub kolekcji języka C#, ponieważ jest to wymagane powiązanie danych z kontrolkami AppKit, takimi jak widoki tabel, widoki konspektu i kolekcje.
  2. Ujawniliśmy tablicę pracowników, odrzucając ją do NSArray elementu na potrzeby powiązania danych i zmieniliśmy jego nazwę sformatowaną w języku C#, Peoplena oczekiwaną przez powiązanie danych w postaci {class_name}Tablica (zwróć uwagę, personModelArray że pierwszy znak został złożony w małym przypadku).

Następnie musimy dodać kilka specjalnie nazwanych metod publicznych, aby obsługiwać kontrolery tablic i kontrolery drzewa:

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

Umożliwiają one kontrolerom żądanie i zmodyfikowanie wyświetlanych danych. Podobnie jak powyżej, NSArray mają one bardzo konkretną konwencję nazewnictwa (która różni się od typowych konwencji nazewnictwa języka C#):

  • addObject: - Dodaje obiekt do tablicy.
  • insertObject:in{class_name}ArrayAtIndex: - Gdzie {class_name} jest nazwą klasy. Ta metoda wstawia obiekt do tablicy w danym indeksie.
  • removeObjectFrom{class_name}ArrayAtIndex: - Gdzie {class_name} jest nazwą klasy. Ta metoda usuwa obiekt w tablicy w danym indeksie.
  • set{class_name}Array: - Gdzie {class_name} jest nazwą klasy. Ta metoda umożliwia zastąpienie istniejącego przenoszenia nowym.

Wewnątrz tych metod opakowaliśmy zmiany w tablicy i WillChangeValue DidChangeValue komunikaty dotyczące zgodności Z usługą KVO.

Na koniec, ponieważ Icon właściwość opiera się na wartości isManager właściwości, zmiany isManager właściwości mogą nie zostać odzwierciedlone w Icon elementach interfejsu użytkownika powiązanego z danymi (podczas KVO):

[Export("Icon")]
public NSImage Icon {
    get {
        if (isManager) {
            return NSImage.ImageNamed ("group.png");
        } else {
            return NSImage.ImageNamed ("user.png");
        }
    }
}

Aby rozwiązać ten błąd, użyjemy następującego kodu:

[Export("isManager")]
public bool isManager {
    get { return _isManager; }
    set {
        WillChangeValue ("isManager");
        WillChangeValue ("Icon");
        _isManager = value;
        DidChangeValue ("isManager");
        DidChangeValue ("Icon");
    }
}

Należy pamiętać, isManager że oprócz własnego klucza, akcesorium wysyła WillChangeValue również komunikaty i DidChangeValue dla Icon klucza, aby zobaczyć również zmianę.

W pozostałej części tego artykułu będziemy używać PersonModel modelu danych.

Proste powiązanie danych

Po zdefiniowaniu modelu danych przyjrzyjmy się prostemu przykładowi powiązania danych w narzędziu Xcode Interface Builder. Na przykład dodajmy formularz do naszej aplikacji Xamarin.Mac, która może służyć do edytowania zdefiniowanego PersonModel powyżej elementu. Dodamy kilka pól tekstowych i pole wyboru, aby wyświetlić i edytować właściwości naszego modelu.

Najpierw dodajmy nowy kontroler widoku do naszego pliku Main.storyboard w narzędziu Interface Builder i nadajmy jej klasie SimpleViewControllernazwę :

Dodawanie nowego kontrolera widoku z klasą o nazwie SimpleViewController.

Następnie wróć do Visual Studio dla komputerów Mac, zmodyfikuj plik SimpleViewController.cs (automatycznie dodany do naszego projektu) i uwidocznij wystąpieniePersonModel, z którego będziemy wiązać formularz. Dodaj następujący kod:

private PersonModel _person = new PersonModel();
...

[Export("Person")]
public PersonModel Person {
    get {return _person; }
    set {
        WillChangeValue ("Person");
        _person = value;
        DidChangeValue ("Person");
    }
}

Następnie po załadowaniu widoku utwórzmy wystąpienie naszego PersonModel obiektu i wypełnimy go następującym kodem:

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;

}

Teraz musimy utworzyć formularz, kliknij dwukrotnie plik Main.storyboard, aby otworzyć go do edycji w narzędziu Interface Builder. Układ formularza w taki sposób, aby wyglądał podobnie do następującego:

Edytowanie scenorysu w programie Xcode

Aby powiązać PersonModel formularz z udostępnionym formularzem Person za pośrednictwem klucza, wykonaj następujące czynności:

  1. Wybierz pole tekstowe Nazwy pracownika i przejdź do inspektora powiązań.

  2. Zaznacz pole Bind to (Powiąż z) i wybierz pozycję Simple View Controller (Prosty kontroler widoku) z listy rozwijanej. Następnie wprowadź wartość self.Person.Name dla ścieżki klucza:

    Wprowadź nazwę kropki samodzielnej osoby dla ścieżki klucza.

  3. Zaznacz pole Tekst zawodu i zaznacz pole Bind to (Powiąż z) i wybierz z listy rozwijanej pozycję Simple View Controller (Prosty kontroler widoku). Następnie wprowadź wartość self.Person.Occupation dla ścieżki klucza:

    Wprowadź self dot Person dot Occupation dla ścieżki klucza.

  4. Zaznacz pole wyboru Employee is a Manager (Pracownik jest menedżerem) i zaznacz pole Bind to (Powiąż z) i wybierz pozycję Simple View Controller (Prosty kontroler widoku) z listy rozwijanej. Następnie wprowadź wartość self.Person.isManager dla ścieżki klucza:

    Wprowadzanie własnej kropki Kropka person kropka isManager dla ścieżki klucza.

  5. Wybierz pole Tekstowe Liczba pracowników zarządzanych, a następnie zaznacz pole Bind to (Powiąż z) i wybierz z listy rozwijanej pozycję Simple View Controller (Prosty kontroler widoku). Następnie wprowadź wartość self.Person.NumberOfEmployees dla ścieżki klucza:

    Wprowadzanie własnej kropki Person dot NumberOfEmployees dla ścieżki klucza.

  6. Jeśli pracownik nie jest menedżerem, chcemy ukryć etykietę zarządzaną liczba pracowników i pole tekstowe.

  7. Wybierz etykietę zarządzaną liczba pracowników, rozwiń opcję Ukryte, a następnie zaznacz pole Bind to (Powiąż z) i wybierz pozycję Simple View Controller (Prosty kontroler widoku) z listy rozwijanej. Następnie wprowadź wartość self.Person.isManager dla ścieżki klucza:

    Wprowadzanie własnej kropki kropka person kropka isManager dla ścieżki klucza dla innych niż menedżerów.

  8. Wybierz NSNegateBoolean z listy rozwijanej Przekształcanie wartości:

    Wybieranie przekształcenia klucza NSNegateBoolean

  9. Informuje to powiązanie danych, że etykieta będzie ukryta, jeśli wartość isManager właściwości to false.

  10. Powtórz kroki 7 i 8 dla pola Tekstowego Liczba pracowników zarządzanych .

  11. Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Jeśli uruchomisz aplikację, wartości z Person właściwości automatycznie wypełnią formularz:

Wyświetlanie formularza wypełnionego automatycznie

Wszelkie zmiany wprowadzone przez użytkowników do formularza zostaną zapisane z powrotem do Person właściwości w kontrolerze widoku. Na przykład usunięcie zaznaczenia pracownik jest menedżerem aktualizuje Person wystąpienie naszego PersonModel , a pole tekstowe liczba pracowników zarządzanych etykiet i pól tekstowych są automatycznie ukryte (za pośrednictwem powiązania danych):

Ukrywanie liczby pracowników dla osób niebędących menedżerami

Powiązanie danych widoku tabeli

Teraz, gdy mamy już podstawowe informacje o powiązaniu danych, przyjrzyjmy się bardziej złożonemu zadaniu powiązania danych przy użyciu kontrolera tablicy i powiązania danych z widokiem tabeli. Aby uzyskać więcej informacji na temat pracy z widokami tabel, zobacz dokumentację widoków tabel.

Najpierw dodajmy nowy kontroler widoku do naszego pliku Main.storyboard w narzędziu Interface Builder i nadajmy jej klasie TableViewControllernazwę :

Dodawanie nowego kontrolera widoku z klasą o nazwie TableViewController.

Następnie zmodyfikujmy plik TableViewController.cs (automatycznie dodany do naszego projektu) i uwidaczniamy tablicę (NSArray) PersonModel klas, z którymi będziemy wiązać formularz. Dodaj następujący kod:

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

Podobnie jak w przypadku powyższej PersonModel klasy w sekcji Definiowanie modelu danych udostępniliśmy cztery specjalnie nazwane metody publiczne, tak aby kontroler tablicy i odczytywał i zapisywał dane z naszej kolekcji PersonModels.

Następnie po załadowaniu widoku musimy wypełnić tablicę następującym kodem:

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

}

Teraz musimy utworzyć widok tabeli, kliknij dwukrotnie plik Main.storyboard, aby otworzyć go do edycji w narzędziu Interface Builder. Układ tabeli w taki sposób, aby wyglądała następująco:

Układanie nowego widoku tabeli

Musimy dodać kontroler tablicy, aby zapewnić powiązane dane do naszej tabeli, wykonaj następujące czynności:

  1. Przeciągnij kontroler tablicy z inspektora biblioteki do edytora interfejsu:

    Wybieranie kontrolera tablicy z biblioteki

  2. Wybierz pozycję Kontroler tablicy w hierarchii interfejsu i przejdź do inspektora atrybutów:

    Wybieranie inspektora atrybutów

  3. Wprowadź PersonModel nazwę klasy, kliknij przycisk Plus i dodaj trzy klucze. Nazwij je Name, Occupation i isManager:

    Dodawanie wymaganych ścieżek klucza do kontrolera obiektów.

  4. Informuje to kontroler tablicy, o czym zarządza tablicą i jakie właściwości powinien uwidocznić (za pośrednictwem kluczy).

  5. Przejdź do inspektora powiązań i w obszarze Tablica zawartości wybierz pozycję Powiąż z i Kontroler widoku tabeli. Wprowadź ścieżkę klucza modelu :self.personModelArray

    Wprowadzanie ścieżki klucza

  6. Spowoduje to powiązania kontrolera tablicy z tablicą PersonModels , która została uwidoczniona na kontrolerze widoku.

Teraz musimy powiązać widok tabeli z kontrolerem tablicy, wykonaj następujące czynności:

  1. Wybierz widok tabeli i inspektora powiązań:

    Wybranie widoku tabeli i inspektora powiązań.

  2. W obszarze wyłączenia spisu treści wybierz pozycję Powiąż z i Kontroler tablicy. Wprowadź arrangedObjects wartość dla pola Klucz kontrolera:

    Definiowanie klucza kontrolera

  3. Wybierz komórkę Widok tabeli w kolumnie Pracownik. W Inspektorze powiązań w obszarze ściągnięć wybierz pozycję Powiąż z i Widok komórki tabeli. Wprowadź objectValue.Name wartość dla ścieżki klucza modelu:

    Ustawianie ścieżki klucza modelu dla kolumny Employee (Pracownik).

  4. objectValue jest bieżącą wartością PersonModel w tablicy zarządzanej przez kontroler tablicy.

  5. Wybierz komórkę Widoku tabeli w kolumnie Zawód. W Inspektorze powiązań w obszarze ściągnięć wybierz pozycję Powiąż z i Widok komórki tabeli. Wprowadź objectValue.Occupation wartość dla ścieżki klucza modelu:

    Ustawianie ścieżki klucza modelu dla kolumny Zawód.

  6. Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Jeśli uruchomimy aplikację, tabela zostanie wypełniona naszą tablicą PersonModels:

Uruchomienie aplikacji, która wypełnia tablicę Obiektów PersonModel.

Powiązanie danych widoku konspektu

powiązanie danych z widokiem konspektu jest bardzo podobne do powiązania z widokiem tabeli. Kluczową różnicą jest to, że będziemy używać kontrolera drzewa zamiast kontrolera tablicy w celu udostępnienia powiązanych danych do widoku konspektu. Aby uzyskać więcej informacji na temat pracy z widokami konspektu, zobacz dokumentację widoków konspektu.

Najpierw dodajmy nowy kontroler widoku do naszego pliku Main.storyboard w narzędziu Interface Builder i nadajmy jej klasie OutlineViewControllernazwę :

Dodanie nowego kontrolera widoku z klasą o nazwie OutlineViewController.

Następnie zmodyfikujmy plik OutlineViewController.cs (który został automatycznie dodany do naszego projektu) i uwidaczniamy tablicę (NSArray) PersonModel klas, z którymi będziemy wiązać formularz. Dodaj następujący kod:

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

Podobnie jak w przypadku powyższej PersonModel klasy w sekcji Definiowanie modelu danych udostępniliśmy cztery specjalnie nazwane metody publiczne, tak aby kontroler drzewa i odczytywał i zapisywał dane z naszej kolekcji PersonModels.

Następnie po załadowaniu widoku musimy wypełnić tablicę następującym kodem:

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);

}

Teraz musimy utworzyć widok konspektu, kliknij dwukrotnie plik Main.storyboard, aby otworzyć go do edycji w narzędziu Interface Builder. Układ tabeli w taki sposób, aby wyglądała następująco:

Tworzenie widoku konspektu

Musimy dodać kontroler drzewa, aby podać powiązane dane do naszego konspektu, wykonaj następujące czynności:

  1. Przeciągnij kontroler drzewa z inspektora biblioteki do edytora interfejsu:

    Wybieranie kontrolera drzewa z biblioteki

  2. Wybierz pozycję Kontroler drzewa w hierarchii interfejsu i przejdź do inspektora atrybutów:

    Wybieranie inspektora atrybutów

  3. Wprowadź PersonModel nazwę klasy, kliknij przycisk Plus i dodaj trzy klucze. Nazwij je Name, Occupation i isManager:

    Dodawanie wymaganych ścieżek kluczy dla modelu PersonModel.

  4. Informuje to kontroler drzewa o zarządzaniu tablicą i właściwości, które powinny uwidocznić (za pośrednictwem kluczy).

  5. W sekcji Kontroler drzewa wprowadź personModelArray wartość Dla elementów podrzędnych, wprowadź NumberOfEmployees wartość w obszarze Liczba i wprowadź wartość isEmployee w obszarze Liść:

    Ustawianie ścieżek klucza kontrolera drzewa

  6. Informuje to kontroler drzewa, gdzie można znaleźć wszystkie węzły podrzędne, ile węzłów podrzędnych istnieje i czy bieżący węzeł ma węzły podrzędne.

  7. Przejdź do Inspektora powiązań i w obszarze Tablica zawartości wybierz pozycję Powiąż z i Właściciel pliku. Wprowadź ścieżkę klucza modelu :self.personModelArray

    Edytowanie ścieżki klucza

  8. Spowoduje to powiązania kontrolera drzewa z tablicą PersonModels , którą uwidoczniliśmy na kontrolerze widoku.

Teraz musimy powiązać widok konspektu z kontrolerem drzewa, wykonaj następujące czynności:

  1. Wybierz widok konspektu, a następnie w inspektorze powiązań wybierz pozycję :

    Wybranie widoku konspektu i inspektora powiązań.

  2. W obszarze wyłączenia zawartości widoku konspektu wybierz pozycję Powiąż z i Kontroler drzewa. Wprowadź arrangedObjects wartość dla pola Klucz kontrolera:

    Ustawianie klucza kontrolera

  3. Wybierz komórkę Widok tabeli w kolumnie Pracownik. W Inspektorze powiązań w obszarze ściągnięć wybierz pozycję Powiąż z i Widok komórki tabeli. Wprowadź objectValue.Name wartość dla ścieżki klucza modelu:

    Wprowadzanie wartości ścieżki klucza modelu objectValue dot Name.

  4. objectValue jest bieżącą PersonModel wartością w tablicy zarządzanej przez kontroler drzewa.

  5. Wybierz komórkę Widoku tabeli w kolumnie Zawód. W Inspektorze powiązań w obszarze ściągnięć wybierz pozycję Powiąż z i Widok komórki tabeli. Wprowadź objectValue.Occupation wartość dla ścieżki klucza modelu:

    Wprowadzanie wartości ścieżki klucza modelu objectValue dot Occupation.

  6. Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Jeśli uruchomimy aplikację, konspekt zostanie wypełniony naszą tablicą PersonModels:

Uruchomienie aplikacji, która wypełnia naszą tablicę Obiektów PersonModel.

Powiązanie danych widoku kolekcji

Powiązanie danych z widokiem kolekcji jest bardzo podobne do powiązania z widokiem tabeli, ponieważ kontroler tablicy służy do udostępniania danych dla kolekcji. Ponieważ widok kolekcji nie ma wstępnie ustawionego formatu wyświetlania, wymagana jest większa praca w celu przekazywania opinii o interakcji użytkownika i śledzenia wyboru użytkownika.

Ważne

Ze względu na problem w programach Xcode 7 i macOS 10.11 (i nowszych) widoki kolekcji nie mogą być używane wewnątrz plików scenorysu (scenorysu). W związku z tym należy nadal używać plików xib w celu zdefiniowania widoków kolekcji dla aplikacji platformy Xamarin.Mac. Aby uzyskać więcej informacji, zobacz dokumentację widoków kolekcji.

Debugowanie awarii natywnych

Pomyłka w powiązaniach danych może spowodować awarię natywną w kodzie niezarządzanym i spowodować całkowite niepowodzenie aplikacji Xamarin.Mac z SIGABRT powodu błędu:

Przykład okna dialogowego awarii natywnej

Zazwyczaj istnieją cztery główne przyczyny awarii natywnych podczas tworzenia powiązania danych:

  1. Model danych nie dziedziczy z NSObject ani podklasy klasy NSObject.
  2. Nie uwidacznialiśmy właściwości Objective-C przy użyciu atrybutu [Export("key-name")] .
  3. Nie zawijaliśmy zmian wartości metody dostępu w wywołaniach WillChangeValue metody i DidChangeValue (określając ten sam klucz co Export atrybut).
  4. W narzędziu Interface Builder istnieje nieprawidłowy lub błędnie wtypowany klucz w inspektorze powiązań.

Dekodowanie awarii

Spowodujemy awarię natywną w powiązaniu danych, aby pokazać, jak ją zlokalizować i naprawić. W narzędziu Interface Builder zmieńmy nasze powiązanie pierwszej etykiety w przykładzie widoku kolekcji z Name na Title:

Edytowanie klucza powiązania

Zapiszmy zmianę, wróćmy do Visual Studio dla komputerów Mac, aby zsynchronizować się z programem Xcode i uruchomić naszą aplikację. Po wyświetleniu widoku kolekcji aplikacja chwilowo ulegnie awarii z SIGABRT powodu błędu (jak pokazano w danych wyjściowych aplikacji w Visual Studio dla komputerów Mac), ponieważ PersonModel właściwość nie uwidacznia właściwości z kluczem Title:

Przykład błędu powiązania

Jeśli przewiniemy w górnej części błędu w danych wyjściowych aplikacji, zobaczymy klucz do rozwiązania problemu:

Znajdowanie problemu w dzienniku błędów

Ten wiersz informuje nas, że klucz Title nie istnieje w obiekcie, z którymi jesteśmy powiązani. Jeśli zmienimy powiązanie z powrotem na Name w narzędziu Interface Builder, zapiszemy, synchronizujemy, skompilujemy i uruchomimy, aplikacja będzie działać zgodnie z oczekiwaniami bez problemu.

Podsumowanie

W tym artykule szczegółowo przedstawiono pracę z powiązaniem danych i kodowaniem klucz-wartość w aplikacji platformy Xamarin.Mac. Najpierw przyjrzeliśmy się uwidacznieniu klasy Objective-C C# przy użyciu kodowania klucz-wartość (KVC) i obserwowania wartości klucz-wartość (KVO). Następnie pokazano, jak używać klasy zgodnej z KVO i powiązać je z elementami interfejsu użytkownika w narzędziu Interface Builder programu Xcode. Na koniec pokazano złożone powiązanie danych przy użyciu kontrolerów tablic i kontrolerów drzewa.