Datenbindung und Schlüsselwertcodierung in Xamarin.Mac
In diesem Artikel wird die Verwendung von Key-Value-Codier- und Key-Value-Observing behandelt, um die Datenbindung an UI-Elemente im Benutzeroberflächen-Generator von Xcode zu ermöglichen.
Übersicht
Beim Arbeiten mit C# und .NET in einer Xamarin.Mac-Anwendung haben Sie Zugriff auf die gleichen Schlüsselwertcodierungs- und Datenbindungstechniken, die ein Entwickler ausführt Objective-C und Xcode ausführt. Da Xamarin.Mac direkt in Xcode integriert ist, können Sie den Schnittstellen-Generator von Xcode zum Binden von Daten mit UI-Elementen verwenden, anstatt Code zu schreiben.
Mithilfe von Schlüsselwertcodierungs- und Datenbindungstechniken in Ihrer Xamarin.Mac-Anwendung können Sie die Menge an Code, den Sie schreiben und Standard, um UI-Elemente aufzufüllen und zu bearbeiten, erheblich verringern. Außerdem profitieren Sie von der weiteren Entkoppelung Ihrer Sicherungsdaten (Datenmodell) von der Front-End-Benutzeroberfläche (Model-View-Controller), was zu einfacheren Standard nachhaltigen, flexibleren Anwendungsdesigns führt.
In diesem Artikel werden die Grundlagen der Arbeit mit Key-Value-Codierung und Datenbindung in einer Xamarin.Mac-Anwendung behandelt. Es wird dringend empfohlen, dass Sie zuerst den Artikel "Hello, Mac " durcharbeiten, insbesondere die Abschnitte "Einführung in Xcode" und "Interface Builder " und "Outlets" und "Actions ", da es sich um wichtige Konzepte und Techniken handelt, die wir in diesem Artikel verwenden werden.
Möglicherweise möchten Sie sich auch die Exposing C#-Klassen /-Methoden im Objective-C Abschnitt des Xamarin.Mac Internals-Dokuments ansehen. Außerdem werden die Register
C#-Klassen und Export
-Attribute erläutert, die zum Verbinden Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.
Was ist key-value coding?
Key-Value Coding (KVC) ist ein Mechanismus für den indirekten Zugriff auf die Eigenschaften eines Objekts mithilfe von Schlüsseln (speziell formatierte Zeichenfolgen), um Eigenschaften zu identifizieren, anstatt über Instanzvariablen oder Accessormethoden (get/set
) darauf zuzugreifen. Durch die Implementierung von schlüsselwertkonformen Accessoren in Ihrer Xamarin.Mac-Anwendung erhalten Sie Zugriff auf andere macOS-Features (früher als OS X bezeichnet), z. B. Key-Value Observing (KVO), Datenbindung, Core Data, Cocoa-Bindungen und Skriptierbarkeit.
Mithilfe von Schlüsselwertcodierungs- und Datenbindungstechniken in Ihrer Xamarin.Mac-Anwendung können Sie die Menge an Code, den Sie schreiben und Standard, um UI-Elemente aufzufüllen und zu bearbeiten, erheblich verringern. Außerdem profitieren Sie von der weiteren Entkoppelung Ihrer Sicherungsdaten (Datenmodell) von der Front-End-Benutzeroberfläche (Model-View-Controller), was zu einfacheren Standard nachhaltigen, flexibleren Anwendungsdesigns führt.
Sehen wir uns beispielsweise die folgende Klassendefinition eines KVC-kompatiblen Objekts an:
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 ()
{
}
}
}
Zunächst registriert das [Register("PersonModel")]
Attribut die Klasse und macht sie Objective-Cverfügbar. Anschließend muss die Klasse von NSObject
(oder einer Unterklasse, von der geerbt wird) erben NSObject
. Dadurch werden mehrere Basismethoden hinzugefügt, mit denen die Klasse KVC-kompatibel sein kann. Als Nächstes macht das [Export("Name")]
Attribut die Name
Eigenschaft verfügbar und definiert den Key-Wert, der später für den Zugriff auf die Eigenschaft über KVC- und KVO-Techniken verwendet wird.
Schließlich muss der Accessor Änderungen an dem Wert der Eigenschaft umschließen können, um key-Value-Beobachtete Änderungen am Wert der Eigenschaft zu sein, und WillChangeValue
DidChangeValue
Methodenaufrufe (angeben denselben Schlüssel wie das Export
Attribut). Zum Beispiel:
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
Dieser Schritt ist sehr wichtig für die Datenbindung im Schnittstellen-Generator von Xcode (wie wir weiter unten in diesem Artikel sehen).
Weitere Informationen finden Sie im Key-Value Coding-Programmierhandbuch von Apple.
Schlüssel und Schlüsselpfade
Ein Schlüssel ist eine Zeichenfolge, die eine bestimmte Eigenschaft eines Objekts identifiziert. In der Regel entspricht ein Schlüssel dem Namen einer Accessormethode in einem codierungskonformen Schlüsselwertobjekt. Schlüssel müssen ASCII-Codierung verwenden, beginnen normalerweise mit einem Kleinbuchstaben und dürfen keine Leerzeichen enthalten. In Anbetracht des obigen Name
Beispiels wäre also ein Key Value-Wert der Name
Eigenschaft der PersonModel
Klasse. Der Schlüssel und der Name der verfügbaren Eigenschaft müssen nicht identisch sein, in den meisten Fällen sind sie jedoch.
Ein Schlüsselpfad ist eine Zeichenfolge mit punkttrennten Schlüsseln, die verwendet werden, um eine Hierarchie von Objekteigenschaften anzugeben, die durchlaufen werden sollen. Die Eigenschaft des ersten Schlüssels in der Sequenz ist relativ zum Empfänger, und jeder nachfolgende Schlüssel wird relativ zum Wert der vorherigen Eigenschaft ausgewertet. Auf die gleiche Weise verwenden Sie die Punktnotation, um ein Objekt und dessen Eigenschaften in einer C#-Klasse zu durchlaufen.
Beispiel: Wenn Sie die PersonModel
Klasse erweitert und Eigenschaft hinzugefügt Child
haben:
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 ()
{
}
}
}
Der Schlüsselpfad zum Namen des untergeordneten Elements wäre self.Child.Name
oder einfach Child.Name
(basierend auf der Verwendung des Schlüsselwerts).
Abrufen von Werten mithilfe der Schlüsselwertcodierung
Die ValueForKey
Methode gibt den Wert für den angegebenen Schlüssel (als a NSString
) relativ zur Instanz der KVC-Klasse zurück, die die Anforderung empfängt. Wenn Person
es sich beispielsweise um eine Instanz der PersonModel
oben definierten Klasse handelt:
// Read value
var name = Person.ValueForKey (new NSString("Name"));
Dadurch wird der Wert der Name
Eigenschaft für diese Instanz zurückgegeben.PersonModel
Festlegen von Werten mithilfe der Schlüsselwertcodierung
Entsprechend wird der SetValueForKey
Wert für den angegebenen Schlüssel (als a NSString
) relativ zur Instanz der KVC-Klasse festgelegt, die die Anforderung empfängt. Verwenden Sie also erneut eine Instanz der PersonModel
Klasse, wie unten dargestellt:
// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));
Würde den Wert der Name
Eigenschaft in Jane Doe
.
Beobachten von Wertänderungen
Mithilfe von Key-Value Observing (KVO) können Sie einen Beobachter an einen bestimmten Schlüssel einer KVC-kompatiblen Klasse anfügen und jedes Mal benachrichtigt werden, wenn der Wert für diesen Schlüssel geändert wird (entweder mithilfe von KVC-Techniken oder direkt auf die angegebene Eigenschaft im C#-Code zugreifen). Zum Beispiel:
// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
// Inform caller of selection change
Console.WriteLine("New Name: {0}", Person.Name)
});
Jedes Mal, wenn die Name
Eigenschaft der Person
Instanz der PersonModel
Klasse geändert wird, wird der neue Wert in die Konsole geschrieben.
Weitere Informationen finden Sie in der Einführung in das Programmierhandbuch für Key-Value Observing von Apple.
Datenbindung
In den folgenden Abschnitten wird gezeigt, wie Sie eine Codierung von Schlüsselwerten und eine Kompatible Klasse für Schlüsselwerte verwenden können, um Daten an UI-Elemente im Schnittstellen-Generator von Xcode zu binden, anstatt Werte mithilfe von C#-Code zu lesen und zu schreiben. Auf diese Weise trennen Sie Ihr Datenmodell von den Ansichten, die zum Anzeigen verwendet werden, wodurch die Xamarin.Mac-Anwendung flexibler und einfacher Standard tain wird. Außerdem verringern Sie die Menge an Code, der geschrieben werden muss.
Definieren des Datenmodells
Bevor Sie ein UI-Element im Schnittstellen-Generator binden können, müssen Sie eine KVC/KVO-kompatible Klasse in Ihrer Xamarin.Mac-Anwendung definieren, um als Datenmodell für die Bindung zu fungieren. Das Datenmodell stellt alle Daten bereit, die auf der Benutzeroberfläche angezeigt werden, und empfängt alle Änderungen an den Daten, die der Benutzer in der Benutzeroberfläche während der Ausführung der Anwendung vornimmt.
Wenn Sie beispielsweise eine Anwendung schreiben, die eine Gruppe von Mitarbeitern verwaltet, können Sie die folgende Klasse verwenden, um das Datenmodell zu definieren:
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
}
}
Die meisten Features dieser Klasse wurden im Abschnitt "Schlüsselwertcodierung " weiter oben behandelt. Sehen wir uns jedoch einige bestimmte Elemente und einige Ergänzungen an, die es dieser Klasse ermöglichen, als Datenmodell für Arraycontroller und Strukturcontroller zu fungieren (die wir später zur Datenbindung von Strukturansichten, Gliederungsansichten und Sammlungsansichten verwenden).
Erstens, da ein Mitarbeiter möglicherweise ein Vorgesetzter ist, haben wir eine NSArray
(insbesondere eine NSMutableArray
Änderung der Werte) verwendet, damit die Mitarbeiter, die sie verwaltet haben, an sie angefügt werden können:
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
Hier sind zwei Punkte zu beachten:
- Wir haben anstelle
NSMutableArray
eines standardmäßigen C#-Arrays oder einer Standardauflistung verwendet, da dies eine Anforderung für die Datenbindung an AppKit-Steuerelemente wie Tabellenansichten, Gliederungsansichten und Auflistungen ist. - Wir haben das Array von Mitarbeitern verfügbar gemacht, indem wir es zu
NSArray
Datenbindungszwecken umwandeln und den formatierten C#-Namen in eine formatierte C#-Datei umwandeln,People
zu einer, die von der Datenbindung erwartet wird,personModelArray
in Der Form {class_name}Array (beachten Sie, dass das erste Zeichen klein geschrieben wurde).
Als Nächstes müssen wir einige speziell benennende öffentliche Methoden hinzufügen, um Arraycontroller und Strukturcontroller zu unterstützen:
[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");
}
Diese ermöglichen es den Controllern, die angezeigten Daten anzufordern und zu ändern. Wie oben dargestellt NSArray
weisen diese eine sehr spezifische Benennungskonvention auf (die sich von den typischen C#-Benennungskonventionen unterscheidet):
addObject:
- Fügt dem Array ein Objekt hinzu.insertObject:in{class_name}ArrayAtIndex:
– Wo{class_name}
ist der Name Ihres Kurses. Diese Methode fügt ein Objekt in das Array bei einem bestimmten Index ein.removeObjectFrom{class_name}ArrayAtIndex:
– Wo{class_name}
ist der Name Ihres Kurses. Mit dieser Methode wird das Objekt im Array bei einem bestimmten Index entfernt.set{class_name}Array:
– Wo{class_name}
ist der Name Ihres Kurses. Mit dieser Methode können Sie das vorhandene Tragen durch eine neue ersetzen.
Innerhalb dieser Methoden haben wir Änderungen an dem Array in WillChangeValue
und DidChangeValue
Nachrichten für die KVO-Compliance umschlossen.
Da die Icon
Eigenschaft auf den Wert der isManager
Eigenschaft basiert, werden Änderungen an der isManager
Eigenschaft möglicherweise nicht in den datengebundenen UI-Elementen (während der Icon
KVO) widerzuspiegeln:
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
Um dies zu korrigieren, verwenden wir den folgenden Code:
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
Beachten Sie, dass der isManager
Accessor zusätzlich zu seinem eigenen Schlüssel auch die WillChangeValue
Und-Nachrichten DidChangeValue
für den Icon
Schlüssel sendet, damit auch die Änderung angezeigt wird.
Wir verwenden das PersonModel
Datenmodell während des restlichen Artikels.
Einfache Datenbindung
Sehen wir uns mit unserem definierten Datenmodell ein einfaches Beispiel für die Datenbindung im Schnittstellen-Generator von Xcode an. Fügen wir beispielsweise ein Formular zu unserer Xamarin.Mac-Anwendung hinzu, die zum Bearbeiten des PersonModel
oben definierten Formulars verwendet werden kann. Wir fügen einige Textfelder und ein Kontrollkästchen zum Anzeigen und Bearbeiten von Eigenschaften unseres Modells hinzu.
Als Erstes fügen wir einen neuen Ansichtscontroller zu unserer Datei "Main.storyboard" im Schnittstellen-Generator hinzu und nennen die KlasseSimpleViewController
:
Kehren Sie als Nächstes zu Visual Studio für Mac zurück, bearbeiten Sie die SimpleViewController.cs-Datei (die automatisch zu unserem Projekt hinzugefügt wurde), und machen Sie eine Instanz der PersonModel
Datenbindung des Formulars verfügbar. Fügen Sie den folgenden Code hinzu:
private PersonModel _person = new PersonModel();
...
[Export("Person")]
public PersonModel Person {
get {return _person; }
set {
WillChangeValue ("Person");
_person = value;
DidChangeValue ("Person");
}
}
Als Nächstes, wenn die Ansicht geladen wird, erstellen wir eine Instanz unserer PersonModel
und füllen sie mit diesem Code auf:
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;
}
Jetzt müssen wir unser Formular erstellen, doppelklicken Sie auf die Datei "Main.storyboard ", um es zum Bearbeiten im Schnittstellen-Generator zu öffnen. Layout the form to look like the following:
Gehen Sie wie folgt vor, um das Formular an das PersonModel
Formular zu binden, das über den Person
Schlüssel verfügbar gemacht wird:
Wählen Sie das Textfeld "Mitarbeitername" aus, und wechseln Sie zum Inspektor für Bindungen.
Aktivieren Sie das Kontrollkästchen "Binden an ", und wählen Sie "Einfacher Ansichtscontroller " aus der Dropdownliste aus. Geben Sie
self.Person.Name
als Nächstes den Schlüsselpfad ein:Aktivieren Sie das Textfeld "Beruf " und aktivieren Sie das Kontrollkästchen "Binden an ", und wählen Sie "Einfacher Ansichtscontroller " aus der Dropdownliste aus. Geben Sie
self.Person.Occupation
als Nächstes den Schlüsselpfad ein:Aktivieren Sie das Kontrollkästchen "Mitarbeiter" als Vorgesetzter , und aktivieren Sie das Kontrollkästchen "Binden an ", und wählen Sie "Einfacher Ansichtscontroller " aus der Dropdownliste aus. Geben Sie
self.Person.isManager
als Nächstes den Schlüsselpfad ein:Wählen Sie das Feld "Anzahl der verwalteten Mitarbeiter" aus, und aktivieren Sie das Kontrollkästchen "Binden an ", und wählen Sie "Einfacher Ansichtscontroller " aus der Dropdownliste aus. Geben Sie
self.Person.NumberOfEmployees
als Nächstes den Schlüsselpfad ein:Wenn der Mitarbeiter kein Vorgesetzter ist, möchten wir die Anzahl der verwalteten Mitarbeiterbezeichnung und das Textfeld ausblenden.
Wählen Sie die Anzahl der verwalteten Bezeichnungen für Mitarbeiter aus, erweitern Sie den ausgeblendeten Turndown, und aktivieren Sie das Kontrollkästchen "Binden an ", und wählen Sie "Einfacher Ansichtscontroller " aus der Dropdownliste aus. Geben Sie
self.Person.isManager
als Nächstes den Schlüsselpfad ein:Wählen Sie
NSNegateBoolean
aus der Dropdownliste "Werttransformer" aus:Dadurch wird die Datenbindung mitgeteilt, dass die Bezeichnung ausgeblendet wird, wenn der Wert der
isManager
Eigenschaft lautetfalse
.Wiederholen Sie die Schritte 7 und 8 für das Feld "Anzahl der mitarbeiterverwalteten Textfeld".
Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um mit Xcode zu synchronisieren.
Wenn Sie die Anwendung ausführen, füllen die Werte aus der Person
Eigenschaft automatisch unser Formular aus:
Alle Änderungen, die die Benutzer am Formular vornehmen, werden in die Person
Eigenschaft im Ansichtscontroller zurückgeschrieben. Das Aufheben der Auswahl von "Mitarbeiter" ist z. B. ein Manager aktualisiert die Person
Instanz unserer PersonModel
Und das Feld "Anzahl der verwalteten Mitarbeiter" und "Textfeld" wird automatisch ausgeblendet (über die Datenbindung):
Datenbindung für Tabellenansichten
Nachdem wir nun über die Grundlagen der Datenbindung verfügen, sehen wir uns eine komplexere Datenbindungsaufgabe mithilfe eines Arraycontrollers und einer Datenbindung an eine Tabellenansicht an. Weitere Informationen zum Arbeiten mit Tabellenansichten finden Sie in der Dokumentation zu Tabellenansichten .
Als Erstes fügen wir einen neuen Ansichtscontroller zu unserer Datei "Main.storyboard" im Schnittstellen-Generator hinzu und nennen die KlasseTableViewController
:
Als Nächstes bearbeiten wir die TableViewController.cs Datei (die automatisch zu unserem Projekt hinzugefügt wurde) und machen ein Array (NSArray
) von PersonModel
Klassen verfügbar, an die wir unser Formular binden werden. Fügen Sie den folgenden Code hinzu:
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");
}
Genau wie in der PersonModel
klasse oben im Abschnitt "Definieren Ihres Datenmodells " haben wir vier speziell benannte öffentliche Methoden verfügbar gemacht, sodass der ArrayController Daten aus unserer Sammlung PersonModels
lesen und schreiben kann.
Als Nächstes, wenn die Ansicht geladen wird, müssen wir unser Array mit diesem Code auffüllen:
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"));
}
Jetzt müssen wir unsere Tabellenansicht erstellen, doppelklicken Sie auf die Datei "Main.storyboard ", um sie zum Bearbeiten im Schnittstellen-Generator zu öffnen. Layouten Sie die Tabelle so, dass sie etwa wie folgt aussieht:
Wir müssen einen Arraycontroller hinzufügen, um gebundene Daten zu unserer Tabelle bereitzustellen. Gehen Sie wie folgt vor:
Ziehen Sie einen Arraycontroller aus dem Bibliotheksinspektor auf den Schnittstellen-Editor:
Wählen Sie den Arraycontroller in der Schnittstellenhierarchie aus, und wechseln Sie zum Attributinspektor:
Geben Sie die EINGABETASTE
PersonModel
für den Klassennamen ein, klicken Sie auf die Schaltfläche "Plus ", und fügen Sie drei Schlüssel hinzu. Benennen Sie sieName
,Occupation
undisManager
:Dies teilt dem Arraycontroller mit, was er für die Verwaltung eines Arrays verwendet, und welche Eigenschaften verfügbar gemacht werden sollen (über Schlüssel).
Wechseln Sie zum Inspektor für Bindungen, und wählen Sie unter "Inhaltsarray" die Option "Binden an" und "Tabellenansichtscontroller" aus. Geben Sie einen Modellschlüsselpfad von
self.personModelArray
:Dadurch wird der Arraycontroller mit dem Array
PersonModels
verbunden, das wir auf unserem Ansichtscontroller verfügbar gemacht haben.
Jetzt müssen wir unsere Tabellenansicht an den Arraycontroller binden, gehen Sie wie folgt vor:
Wählen Sie die Tabellenansicht und den Bindungsinspektor aus:
Wählen Sie unter dem Turndown "Tabelleninhalte " die Option "Binden an " und "Arraycontroller" aus. Eingabe
arrangedObjects
für das Feld "Controllerschlüssel ":Wählen Sie die Tabellenansichtszelle unter der Spalte "Mitarbeiter " aus. Wählen Sie im Bindungen-Inspektor unter dem Wert-Turndown die Option "Binden an" und "Tabellenzellenansicht" aus. Geben Sie
objectValue.Name
für den Modellschlüsselpfad ein:objectValue
ist der AktuellePersonModel
im Array, das vom Arraycontroller verwaltet wird.Wählen Sie die Tabellenansichtszelle unter der Spalte "Beruf " aus. Wählen Sie im Bindungen-Inspektor unter dem Wert-Turndown die Option "Binden an" und "Tabellenzellenansicht" aus. Geben Sie
objectValue.Occupation
für den Modellschlüsselpfad ein:Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um mit Xcode zu synchronisieren.
Wenn wir die Anwendung ausführen, wird die Tabelle mit unserem Array von PersonModels
:
Datenbindung in der Gliederungsansicht
Die Datenbindung für eine Gliederungsansicht ähnelt sehr der Bindung für eine Tabellenansicht. Der Hauptunterschied besteht darin, dass wir einen Strukturcontroller anstelle eines Arraycontrollers verwenden, um die gebundenen Daten für die Gliederungsansicht bereitzustellen. Weitere Informationen zum Arbeiten mit Gliederungsansichten finden Sie in unserer Dokumentation zu Gliederungsansichten .
Als Erstes fügen wir einen neuen Ansichtscontroller zu unserer Datei "Main.storyboard" im Schnittstellen-Generator hinzu und nennen die KlasseOutlineViewController
:
Als Nächstes bearbeiten wir die OutlineViewController.cs Datei (die automatisch zu unserem Projekt hinzugefügt wurde) und machen ein Array (NSArray
) von PersonModel
Klassen verfügbar, an die wir unser Formular binden werden. Fügen Sie den folgenden Code hinzu:
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");
}
Genau wie im PersonModel
Abschnitt "Definieren Des Datenmodells " haben wir vier speziell benannte öffentliche Methoden verfügbar gemacht, damit der Strukturcontroller Daten aus unserer Sammlung PersonModels
lesen und schreiben kann.
Als Nächstes, wenn die Ansicht geladen wird, müssen wir unser Array mit diesem Code auffüllen:
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);
}
Jetzt müssen wir unsere Gliederungsansicht erstellen, doppelklicken Sie auf die Datei "Main.storyboard ", um sie zum Bearbeiten im Schnittstellen-Generator zu öffnen. Layouten Sie die Tabelle so, dass sie etwa wie folgt aussieht:
Wir müssen einen Strukturverantwortlichen hinzufügen, um gebundene Daten zu unserer Gliederung bereitzustellen, gehen Sie wie folgt vor:
Ziehen Sie einen Strukturcontroller aus dem Bibliotheksinspektor auf den Schnittstellen-Editor:
Wählen Sie den Strukturcontroller in der Schnittstellenhierarchie aus, und wechseln Sie zum Attributinspektor:
Geben Sie die EINGABETASTE
PersonModel
für den Klassennamen ein, klicken Sie auf die Schaltfläche "Plus ", und fügen Sie drei Schlüssel hinzu. Benennen Sie sieName
,Occupation
undisManager
:Dadurch wird dem Strukturcontroller mitgeteilt, was er für die Verwaltung eines Arrays verwendet, und welche Eigenschaften verfügbar gemacht werden sollen (über Schlüssel).
Geben Sie unter dem Abschnitt "Strukturcontroller" die Zeichenfolge "Untergeordnete Elemente" ein, geben Sie
NumberOfEmployees
unter "Anzahl" ein, und geben Sie unter "Blatt" einisEmployee
:personModelArray
Dadurch wird dem Strukturcontroller mitgeteilt, wo untergeordnete Knoten gefunden werden sollen, wie viele untergeordnete Knoten vorhanden sind und ob der aktuelle Knoten untergeordnete Knoten aufweist.
Wechseln Sie zum Inspektor für Bindungen, und wählen Sie unter "Inhaltsarray" die Option "An den Besitzer der Datei binden" und "Dateibesitzer" aus. Geben Sie einen Modellschlüsselpfad von
self.personModelArray
:Dadurch wird der Strukturcontroller mit dem Array
PersonModels
verknüpft, das wir auf unserem Ansichtscontroller verfügbar gemacht haben.
Jetzt müssen wir unsere Gliederungsansicht an den Strukturcontroller binden, gehen Sie wie folgt vor:
Wählen Sie die Gliederungsansicht aus, und wählen Sie im Bindungsinspektor Folgendes aus:
Wählen Sie im Turndown der Gliederungsansicht "Inhalt " die Option "Binden an " und "Strukturcontroller" aus. Eingabe
arrangedObjects
für das Feld "Controllerschlüssel ":Wählen Sie die Tabellenansichtszelle unter der Spalte "Mitarbeiter " aus. Wählen Sie im Bindungen-Inspektor unter dem Wert-Turndown die Option "Binden an" und "Tabellenzellenansicht" aus. Geben Sie
objectValue.Name
für den Modellschlüsselpfad ein:objectValue
ist der AktuellePersonModel
im Array, das vom Strukturcontroller verwaltet wird.Wählen Sie die Tabellenansichtszelle unter der Spalte "Beruf " aus. Wählen Sie im Bindungen-Inspektor unter dem Wert-Turndown die Option "Binden an" und "Tabellenzellenansicht" aus. Geben Sie
objectValue.Occupation
für den Modellschlüsselpfad ein:Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um mit Xcode zu synchronisieren.
Wenn wir die Anwendung ausführen, wird die Gliederung mit unserem Array von PersonModels
:
Datenbindung der Sammlungsansicht
Die Datenbindung mit einer Sammlungsansicht ähnelt der Bindung mit einer Tabellenansicht, da ein Arraycontroller verwendet wird, um Daten für die Sammlung bereitzustellen. Da die Sammlungsansicht nicht über ein voreingestelltes Anzeigeformat verfügt, ist mehr Arbeit erforderlich, um Feedback zur Benutzerinteraktion bereitzustellen und die Benutzerauswahl nachzuverfolgen.
Wichtig
Aufgrund eines Problems in Xcode 7 und macOS 10.11 (und höher) können Sammlungsansichten nicht innerhalb einer Storyboarddateien (Storyboard) verwendet werden. Daher müssen Sie weiterhin XIB-Dateien verwenden, um Ihre Sammlungsansichten für Ihre Xamarin.Mac-Apps zu definieren. Weitere Informationen finden Sie in der Dokumentation zu Sammlungsansichten .
Debuggen systemeigener Abstürze
Wenn Sie einen Fehler in Ihren Datenbindungen machen, kann ein systemeigener Absturz in nicht verwaltetem Code auftreten und dazu führen, dass Ihre Xamarin.Mac-Anwendung vollständig mit einem SIGABRT
Fehler fehlschlägt:
Normalerweise gibt es vier Hauptursachen für systemeigene Abstürze während der Datenbindung:
- Ihr Datenmodell erbt nicht von
NSObject
oder einer Unterklasse vonNSObject
. - Sie haben Ihre Eigenschaft nicht für Objective-C die Verwendung des
[Export("key-name")]
Attributs verfügbar gemacht. - Sie haben keine Änderungen am Wert des Accessors in
WillChangeValue
undDidChangeValue
Methodenaufrufe umbrochen (angeben denselben Schlüssel wie dasExport
Attribut). - Sie haben einen falschen oder falsch eingegebenen Schlüssel im Bindungsinspektor im Schnittstellen-Generator.
Decodieren eines Absturzes
Lassen Sie uns einen systemeigenen Absturz in unserer Datenbindung verursachen, damit wir zeigen können, wie sie gefunden und behoben werden können. Im Schnittstellen-Generator ändern wir unsere Bindung des ersten Bezeichnungsbeispiels in der Sammlungsansicht von Name
:Title
Lassen Sie uns die Änderung speichern, zurück zu Visual Studio für Mac wechseln, um mit Xcode zu synchronisieren und unsere Anwendung auszuführen. Wenn die Sammlungsansicht angezeigt wird, stürzt die Anwendung momentan mit einem SIGABRT
Fehler ab (wie in der Anwendungsausgabe in Visual Studio für Mac dargestellt), da die PersonModel
Eigenschaft mit dem Schlüssel Title
nicht verfügbar gemacht wird:
Wenn ein Bildlauf zum Anfang des Fehlers in der Anwendungsausgabe erfolgt , wird der Schlüssel zum Beheben des Problems angezeigt:
Diese Zeile teilt uns mit, dass der Schlüssel Title
für das Objekt, an das wir binden, nicht vorhanden ist. Wenn wir die Bindung wieder Name
in den Schnittstellen-Generator ändern, speichern, synchronisieren, neu erstellen und ausführen, wird die Anwendung wie erwartet ausgeführt.
Zusammenfassung
Dieser Artikel hat einen detaillierten Blick auf die Arbeit mit datenbindung und Key-Value-Codierung in einer Xamarin.Mac-Anwendung gemacht. Zunächst wurde eine C#-Klasse Objective-C mithilfe von Schlüsselwertcodierung (Key-Value Coding, KVC) und Key-Value Observing (KVO) bereitgestellt. Als Nächstes wurde gezeigt, wie sie eine KVO-kompatible Klasse und Datenbindung an UI-Elemente im Schnittstellen-Generator von Xcode verwenden. Schließlich wurde eine komplexe Datenbindung mithilfe von Arraycontrollern und Strukturcontrollern gezeigt.
Verwandte Links
- Hello, Mac (Hallo, Mac)
- Standardsteuerelemente
- Tabellenansichten
- Gliederungsansichten
- Sammlungsansichten
- Programmierhandbuch zur Schlüsselwertcodierung
- Einführung in das Programmierhandbuch für Key-Value-Observing
- Einführung in Die Programmierungsthemen zu Kakaobindungen
- Einführung in die Cocoa Bindings-Referenz
- NSCollectionView
- macOS-Eingaberichtlinien