Data binding e codifica chiave-valore in Xamarin.Mac
Questo articolo illustra l'uso della codifica chiave-valore e dell'osservazione chiave-valore per consentire il data binding agli elementi dell'interfaccia utente in Interface Builder di Xcode.
Panoramica
Quando si lavora con C# e .NET in un'applicazione Xamarin.Mac, è possibile accedere alle stesse tecniche di codifica chiave-valore e di data binding utilizzate da uno sviluppatore in Objective-C e Xcode . Poiché Xamarin.Mac si integra direttamente con Xcode, è possibile usare Interface Builder di Xcode per Data Bind con elementi dell'interfaccia utente invece di scrivere codice.
Usando tecniche di codifica chiave-valore e data binding nell'applicazione Xamarin.Mac, è possibile ridurre notevolmente la quantità di codice che è necessario scrivere e gestire per popolare e usare gli elementi dell'interfaccia utente. È anche possibile separare ulteriormente i dati di backup (Modello di dati) dall'interfaccia utente front-end (Model-View-Controller), semplificando la gestione e la progettazione di applicazioni più flessibili.
In questo articolo verranno illustrate le nozioni di base sull'uso della codifica chiave-valore e del data binding in un'applicazione Xamarin.Mac. È consigliabile usare prima di tutto l'articolo Hello, Mac , in particolare le sezioni Introduzione a Xcode e Interface Builder e Outlet e Actions , in quanto illustra i concetti e le tecniche chiave che verranno usati in questo articolo.
È possibile esaminare anche la sezione Esposizione di classi/metodi C# al Objective-C documento Internals di Xamarin.Mac, che illustra gli Register
attributi e Export
usati per collegare le classi C# agli oggetti e agli Objective-C elementi dell'interfaccia utente.
Che cos'è la codifica chiave-valore
La codifica chiave-valore (KVC) è un meccanismo per accedere indirettamente alle proprietà di un oggetto, usando chiavi (stringhe formattate appositamente) per identificare le proprietà anziché accedervi tramite variabili di istanza o metodi di accesso (get/set
). Implementando funzioni di accesso conformi alla codifica chiave-valore nell'applicazione Xamarin.Mac, si ottiene l'accesso ad altre funzionalità macOS (in precedenza note come OS X), come l'osservazione chiave-valore (KVO), il data binding, Core Data, le associazioni cocoa e la scriptability.
Usando tecniche di codifica chiave-valore e data binding nell'applicazione Xamarin.Mac, è possibile ridurre notevolmente la quantità di codice che è necessario scrivere e gestire per popolare e usare gli elementi dell'interfaccia utente. È anche possibile separare ulteriormente i dati di backup (Modello di dati) dall'interfaccia utente front-end (Model-View-Controller), semplificando la gestione e la progettazione di applicazioni più flessibili.
Si esaminerà ad esempio la definizione di classe seguente di un oggetto conforme a 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 ()
{
}
}
}
Prima di tutto, l'attributo [Register("PersonModel")]
registra la classe e la espone a Objective-C. Quindi, la classe deve ereditare da NSObject
(o una sottoclasse che eredita da NSObject
), questo aggiunge diversi metodi di base che consentono alla classe di essere conformi a KVC. Successivamente, l'attributo [Export("Name")]
espone la Name
proprietà e definisce il valore Key che verrà usato successivamente per accedere alla proprietà tramite le tecniche KVC e KVO.
Infine, per essere in grado di essere Key-Value Observed modifiche apportate al valore della proprietà, la funzione di accesso deve eseguire il wrapping delle modifiche apportate al relativo valore nelle WillChangeValue
chiamate al metodo e DidChangeValue
specificando la stessa chiave dell'attributo Export
. Ad esempio:
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
Questo passaggio è molto importante per il data binding in Interface Builder di Xcode(come vedremo più avanti in questo articolo).
Per altre informazioni, vedere la Guida alla programmazione della codifica chiave-valore di Apple.
Chiavi e percorsi chiave
Una chiave è una stringa che identifica una proprietà specifica di un oggetto . In genere, una chiave corrisponde al nome di un metodo della funzione di accesso in un oggetto conforme alla codifica chiave-valore. Le chiavi devono usare la codifica ASCII, in genere iniziano con una lettera minuscola e potrebbero non contenere spazi vuoti. Quindi, dato l'esempio precedente, Name
sarebbe un valore chiave della Name
proprietà della PersonModel
classe . La chiave e il nome della proprietà che espongono non devono essere uguali, ma nella maggior parte dei casi sono.
Un percorso chiave è una stringa di chiavi separate da punti usati per specificare una gerarchia di proprietà dell'oggetto da attraversare. La proprietà della prima chiave nella sequenza è relativa al ricevitore e ogni chiave successiva viene valutata rispetto al valore della proprietà precedente. Allo stesso modo si usa la notazione punto per attraversare un oggetto e le relative proprietà in una classe C#.
Ad esempio, se è stata espansa la PersonModel
classe e la proprietà aggiunta 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 ()
{
}
}
}
Il percorso chiave del nome dell'elemento figlio sarebbe self.Child.Name
o semplicemente Child.Name
(in base alla modalità di utilizzo del valore chiave).
Recupero di valori tramite la codifica chiave-valore
Il ValueForKey
metodo restituisce il valore per la chiave specificata (come ), NSString
rispetto all'istanza della classe KVC che riceve la richiesta. Ad esempio, se Person
è un'istanza della PersonModel
classe definita in precedenza:
// Read value
var name = Person.ValueForKey (new NSString("Name"));
Verrà restituito il valore della proprietà per l'istanza Name
di PersonModel
.
Impostazione dei valori tramite la codifica chiave-valore
Analogamente, SetValueForKey
impostare il valore per la chiave specificata (come ), NSString
rispetto all'istanza della classe KVC che riceve la richiesta. Quindi, anche in questo caso, usando un'istanza della PersonModel
classe , come illustrato di seguito:
// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));
Modificare il valore della Name
proprietà in Jane Doe
.
Osservazione delle modifiche dei valori
Usando l'osservazione chiave-valore (KVO), è possibile associare un osservatore a una chiave specifica di una classe conforme a KVC e ricevere una notifica ogni volta che il valore per tale chiave viene modificato (usando tecniche KVC o accedendo direttamente alla proprietà specificata nel codice C#). Ad esempio:
// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
// Inform caller of selection change
Console.WriteLine("New Name: {0}", Person.Name)
});
Ora, ogni volta che la Name
proprietà dell'istanza Person
della PersonModel
classe viene modificata, il nuovo valore viene scritto nella console.
Per altre informazioni, vedere Introduzione a Key-Value Observing Programming Guide (Introduzione a Key-Value Observing Programming Guide) di Apple.
Data binding
Le sezioni seguenti illustrano come usare una classe conforme a codice chiave-valore e chiave-valore per associare i dati agli elementi dell'interfaccia utente in Interface Builder di Xcode, invece di leggere e scrivere valori usando il codice C#. In questo modo si separa il modello di dati dalle viste usate per visualizzarle, rendendo l'applicazione Xamarin.Mac più flessibile e più semplice da gestire. Si riduce notevolmente anche la quantità di codice che deve essere scritta.
Definizione del modello di dati
Prima di poter associare dati a un elemento dell'interfaccia utente in Interface Builder, è necessario avere una classe conforme a KVC/KVO definita nell'applicazione Xamarin.Mac per fungere da modello di dati per l'associazione. Il modello di dati fornisce tutti i dati che verranno visualizzati nell'interfaccia utente e riceve tutte le modifiche ai dati apportati dall'utente nell'interfaccia utente durante l'esecuzione dell'applicazione.
Ad esempio, se si scrive un'applicazione che ha gestito un gruppo di dipendenti, è possibile usare la classe seguente per definire il modello di dati:
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
}
}
La maggior parte delle funzionalità di questa classe è stata illustrata nella sezione Che cos'è la codifica chiave-valore precedente. Verranno tuttavia esaminati alcuni elementi specifici e alcune aggiunte che sono state apportate per consentire a questa classe di fungere da modello di dati per controller di matrice e controller dell'albero, che verranno usati in un secondo momento per associare le viste albero, le visualizzazioni struttura e le visualizzazioni raccolta.
In primo luogo, poiché un dipendente potrebbe essere un manager, è stato usato un NSArray
oggetto (in particolare, NSMutableArray
in modo che i valori possano essere modificati) per consentire ai dipendenti che sono riusciti ad essere collegati a loro:
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
Due aspetti da notare qui:
- È stata usata una
NSMutableArray
matrice o una raccolta C# standard perché si tratta di un requisito per l'associazione di dati ai controlli AppKit, ad esempio visualizzazioni tabella, visualizzazioni struttura e raccolte. - È stata esposta la matrice di dipendenti eseguendone il cast a per
NSArray
scopi di data binding e modificandone il nome formattato C#,People
, in uno previsto dal data binding,personModelArray
nel formato {class_name}Array (si noti che il primo carattere è stato fatto in minuscolo).
Successivamente, è necessario aggiungere alcuni metodi pubblici con nomi specifici per supportare i controller array e i controller albero:
[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");
}
Questi consentono ai titolari del trattamento di richiedere e modificare i dati visualizzati. Come illustrato in precedenza NSArray
, questi hanno una convenzione di denominazione molto specifica (diversa dalle convenzioni di denominazione C# tipiche):
addObject:
- Aggiunge un oggetto alla matrice.insertObject:in{class_name}ArrayAtIndex:
- Dove{class_name}
è il nome della classe. Questo metodo inserisce un oggetto nella matrice in corrispondenza di un determinato indice.removeObjectFrom{class_name}ArrayAtIndex:
- Dove{class_name}
è il nome della classe. Questo metodo rimuove l'oggetto nella matrice in corrispondenza di un determinato indice.set{class_name}Array:
- Dove{class_name}
è il nome della classe. Questo metodo consente di sostituire il trasporto esistente con uno nuovo.
All'interno di questi metodi è stato eseguito il wrapping delle modifiche apportate alla matrice in WillChangeValue
e DidChangeValue
ai messaggi per la conformità KVO.
Infine, poiché la Icon
proprietà si basa sul valore della isManager
proprietà , le modifiche apportate alla isManager
proprietà potrebbero non essere riflesse negli elementi dell'interfaccia Icon
utente associati a dati (durante KVO):
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
Per correggere questo errore, viene usato il codice seguente:
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
Si noti che oltre alla propria chiave, la isManager
funzione di accesso invia anche i WillChangeValue
messaggi e DidChangeValue
per la Icon
chiave in modo che visualizzi anche la modifica.
Nel resto di questo articolo verrà usato il PersonModel
modello di dati.
Data binding semplice
Dopo aver definito il modello di dati, si esaminerà un semplice esempio di data binding in Interface Builder di Xcode. Ad esempio, aggiungere un modulo all'applicazione Xamarin.Mac che può essere usata per modificare l'oggetto PersonModel
definito in precedenza. Verranno aggiunti alcuni campi di testo e una casella di controllo per visualizzare e modificare le proprietà del modello.
Aggiungere prima di tutto un nuovo controller di visualizzazione al file Main.storyboard in Interface Builder e denominare la classe SimpleViewController
:
Tornare quindi a Visual Studio per Mac, modificare il file di SimpleViewController.cs (aggiunto automaticamente al progetto) ed esporre un'istanza PersonModel
di a cui verrà eseguito il data binding del modulo. Aggiungere il codice seguente:
private PersonModel _person = new PersonModel();
...
[Export("Person")]
public PersonModel Person {
get {return _person; }
set {
WillChangeValue ("Person");
_person = value;
DidChangeValue ("Person");
}
}
Successivamente, quando viene caricata la visualizzazione, creare un'istanza di PersonModel
e popolarla con questo codice:
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;
}
A questo punto è necessario creare il modulo, fare doppio clic sul file Main.storyboard per aprirlo per la modifica in Interface Builder. Layout del modulo in modo che sia simile al seguente:
Per associare il modulo all'oggetto PersonModel
esposto tramite la Person
chiave, eseguire le operazioni seguenti:
Selezionare il campo Testo nome dipendente e passare a Controllo associazioni.
Selezionare la casella Associa a e selezionare Simple View Controller (Controller visualizzazione semplice) nell'elenco a discesa.
self.Person.Name
Immettere quindi per Il percorso chiave:Selezionare il campo Testo occupazione e selezionare la casella Associa a e selezionare Simple View Controller (Controller visualizzazione semplice) nell'elenco a discesa.
self.Person.Occupation
Immettere quindi per Il percorso chiave:Selezionare la casella di controllo Employee is a Manager (Dipendente è manager) e selezionare Bind to ( Associa a ) e selezionare Simple View Controller (Controller visualizzazione semplice) nell'elenco a discesa.
self.Person.isManager
Immettere quindi per Il percorso chiave:Selezionare il campo Number of Employees Managed Text (Numero di dipendenti gestiti ) e selezionare Bind to (Associa a ) e selezionare Simple View Controller (Controller visualizzazione semplice) nell'elenco a discesa.
self.Person.NumberOfEmployees
Immettere quindi per Il percorso chiave:Se il dipendente non è un responsabile, si vuole nascondere il campo Numero di dipendenti gestiti e testo.
Selezionare l'etichetta gestita Numero di dipendenti, espandere il menu a discesa Nascosto e selezionare Associa a e selezionare Simple View Controller (Controller visualizzazione semplice) dall'elenco a discesa.
self.Person.isManager
Immettere quindi per Il percorso chiave:Selezionare dall'elenco a discesa Value Transformer:Select
NSNegateBoolean
from the Value Transformer dropdown:Indica al data binding che l'etichetta verrà nascosta se il valore della
isManager
proprietà èfalse
.Ripetere i passaggi 7 e 8 per il campo Numero di dipendenti gestiti testo.
Salvare le modifiche e tornare a Visual Studio per Mac per la sincronizzazione con Xcode.
Se si esegue l'applicazione, i valori della proprietà popolano automaticamente il Person
modulo:
Tutte le modifiche apportate dagli utenti al modulo verranno riscritto nella Person
proprietà nel controller di visualizzazione. Ad esempio, deselezionare Employee è un manager che aggiorna l'istanza Person
di PersonModel
e il campo di testo e l'etichetta gestita Numero di dipendenti vengono nascosti automaticamente (tramite il data binding):
Associazione dati vista tabella
Ora che sono disponibili le nozioni di base del data binding, si esaminerà un'attività di data binding più complessa usando un controller di matrice e il data binding a una vista tabella. Per altre informazioni sull'uso delle viste tabella, vedere la documentazione delle viste tabella.
Aggiungere prima di tutto un nuovo controller di visualizzazione al file Main.storyboard in Interface Builder e denominare la classe TableViewController
:
Successivamente, modificare il file TableViewController.cs (che è stato aggiunto automaticamente al progetto) ed esporre una matrice (NSArray
) di PersonModel
classi a cui verrà eseguito il data binding del modulo. Aggiungere il codice seguente:
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");
}
Proprio come nella PersonModel
classe precedente nella sezione Definizione del modello di dati, sono stati esposti quattro metodi pubblici denominati appositamente in modo che il controller array e legga e scriva i dati dalla raccolta di PersonModels
.
Al termine del caricamento della visualizzazione, è necessario popolare la matrice con questo codice:
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"));
}
A questo punto è necessario creare la visualizzazione tabella, fare doppio clic sul file Main.storyboard per aprirlo per la modifica in Interface Builder. Layout della tabella in modo che sia simile al seguente:
È necessario aggiungere un controller di matrice per fornire i dati associati alla tabella, eseguire le operazioni seguenti:
Trascinare un controller di matrice da Controllo libreria nell'editor dell'interfaccia:
Selezionare Controller matrice nella gerarchia dell'interfaccia e passare a Controllo attributi:
Immettere
PersonModel
per Nome classe, fare clic sul pulsante Plus e aggiungere tre chiavi. DenominarliName
eOccupation
isManager
:In questo modo il controller array indica di cosa gestisce una matrice di e di quali proprietà deve esporre (tramite chiavi).
Passare a Binding Inspector (Controllo associazioni ) e in Content Array (Matrice di contenuto) selezionare Bind to and Table View Controller (Associa a e controller visualizzazione tabella). Immettere un percorso chiave modello di
self.personModelArray
:Questo collega il controller di matrice alla matrice di
PersonModels
che è stata esposta nel controller di visualizzazione.
A questo scopo, è necessario associare la visualizzazione tabella al controller di matrice, eseguire le operazioni seguenti:
Selezionare la visualizzazione Tabella e il controllo binding:
Nell'elenco a discesa Sommario selezionare Associa a e Controller di matrice. Immettere
arrangedObjects
per il campo Controller Key (Chiave controller):Selezionare la cella Visualizzazione tabella nella colonna Employee . In Binding Inspector (Controllo associazioni) sotto l'opzione Value (Valore) selezionare Bind to (Associa a) e Table Cell View (Visualizza cella tabella). Immettere
objectValue.Name
per model key path (Percorso chiave modello):objectValue
è l'oggetto correntePersonModel
nella matrice gestita dal controller di matrice.Selezionare la cella Visualizzazione tabella nella colonna Occupazione . In Binding Inspector (Controllo associazioni) sotto l'opzione Value (Valore) selezionare Bind to (Associa a) e Table Cell View (Visualizza cella tabella). Immettere
objectValue.Occupation
per model key path (Percorso chiave modello):Salvare le modifiche e tornare a Visual Studio per Mac per la sincronizzazione con Xcode.
Se si esegue l'applicazione, la tabella verrà popolata con la matrice di PersonModels
:
Associazione dati visualizzazione struttura
il data binding rispetto a una visualizzazione struttura è molto simile all'associazione a una vista tabella. La differenza principale è che si userà un controller albero anziché un controller di matrice per fornire i dati associati alla visualizzazione struttura. Per altre informazioni sull'uso delle visualizzazioni struttura, vedere la documentazione sulle visualizzazioni struttura.
Aggiungere prima di tutto un nuovo controller di visualizzazione al file Main.storyboard in Interface Builder e denominare la classe OutlineViewController
:
Successivamente, modificare il file OutlineViewController.cs (che è stato aggiunto automaticamente al progetto) ed esporre una matrice (NSArray
) di PersonModel
classi a cui verrà eseguito il data binding del modulo. Aggiungere il codice seguente:
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");
}
Proprio come è stato fatto nella PersonModel
classe precedente nella sezione Definizione del modello di dati, sono stati esposti quattro metodi pubblici denominati appositamente in modo che tree controller e leggere e scrivere dati dalla raccolta di PersonModels
.
Al termine del caricamento della visualizzazione, è necessario popolare la matrice con questo codice:
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);
}
A questo punto è necessario creare la visualizzazione struttura, fare doppio clic sul file Main.storyboard per aprirlo per la modifica in Interface Builder. Layout della tabella in modo che sia simile al seguente:
È necessario aggiungere un controller albero per fornire i dati associati alla struttura, eseguire le operazioni seguenti:
Trascinare un controller albero da Controllo libreria nell'editor dell'interfaccia:
Selezionare Tree Controller (Controller albero) nella gerarchia dell'interfaccia e passare a Attribute Inspector (Controllo attributi):
Immettere
PersonModel
per Nome classe, fare clic sul pulsante Plus e aggiungere tre chiavi. DenominarliName
eOccupation
isManager
:In questo modo, il controller albero indica di cosa gestisce una matrice di e di quali proprietà deve esporre (tramite chiavi).
Nella sezione Controller albero immettere
personModelArray
per Children (Figli), immettereNumberOfEmployees
in Count (Conteggio) e immettereisEmployee
in Leaf (Foglia):In questo modo viene indicato al controller albero dove trovare i nodi figlio, il numero di nodi figlio presenti e se il nodo corrente ha nodi figlio.
Passare a Controllo associazioni e in Matrice di contenuto selezionare Associa a e Proprietario del file. Immettere un percorso chiave modello di
self.personModelArray
:Questo collega il controller albero alla matrice di
PersonModels
che abbiamo esposto nel controller di visualizzazione.
A questo scopo, è necessario associare la visualizzazione Struttura al controller dell'albero, eseguire le operazioni seguenti:
Selezionare la visualizzazione Struttura e in Controllo associazione selezionare :
Nell'elenco a discesa Contenuto visualizzazione struttura selezionare Associa a e Controller albero. Immettere
arrangedObjects
per il campo Controller Key (Chiave controller):Selezionare la cella Visualizzazione tabella nella colonna Employee . In Binding Inspector (Controllo associazioni) sotto l'opzione Value (Valore) selezionare Bind to (Associa a) e Table Cell View (Visualizza cella tabella). Immettere
objectValue.Name
per model key path (Percorso chiave modello):objectValue
è l'oggetto correntePersonModel
nella matrice gestita dal controller albero.Selezionare la cella Visualizzazione tabella nella colonna Occupazione . In Binding Inspector (Controllo associazioni) sotto l'opzione Value (Valore) selezionare Bind to (Associa a) e Table Cell View (Visualizza cella tabella). Immettere
objectValue.Occupation
per model key path (Percorso chiave modello):Salvare le modifiche e tornare a Visual Studio per Mac per la sincronizzazione con Xcode.
Se si esegue l'applicazione, la struttura verrà popolata con la matrice di PersonModels
:
Data binding di visualizzazione raccolta
Il data binding con una visualizzazione raccolta è molto simile all'associazione con una vista tabella, perché un controller di matrice viene usato per fornire dati per la raccolta. Poiché la visualizzazione raccolta non ha un formato di visualizzazione predefinito, è necessario più lavoro per fornire commenti e suggerimenti sull'interazione dell'utente e tenere traccia della selezione dell'utente.
Importante
A causa di un problema in Xcode 7 e macOS 10.11 (e versioni successive), le visualizzazioni della raccolta non possono essere usate all'interno di un file Storyboard (con estensione storyboard). Di conseguenza, sarà necessario continuare a usare i file con estensione xib per definire le visualizzazioni della raccolta per le app Xamarin.Mac. Per altre informazioni, vedere la documentazione delle visualizzazioni raccolte.
Debug di arresti anomali nativi
Se si commette un errore nei data binding, è possibile che si verifica un arresto anomalo nativo nel codice non gestito e che l'applicazione Xamarin.Mac non riesca completamente con un SIGABRT
errore:
Durante il data binding sono in genere presenti quattro cause principali di arresti anomali nativi:
- Il modello di dati non eredita da
NSObject
o da una sottoclasse diNSObject
. - Non è stata esposta la proprietà all'uso Objective-C dell'attributo
[Export("key-name")]
. - Non sono state apportate modifiche al valore della funzione di accesso nelle
WillChangeValue
chiamate al metodo eDidChangeValue
, specificando la stessa chiave dell'attributoExport
. - Si dispone di una chiave errata o digitata in Binding Inspector in Interface Builder.
Decodifica di un arresto anomalo
Si verificherà un arresto anomalo nativo nel data binding per illustrare come individuarlo e risolverlo. In Interface Builder modificare il binding della prima etichetta nell'esempio di visualizzazione raccolta da Name
a Title
:
Salvare la modifica, tornare a Visual Studio per Mac per eseguire la sincronizzazione con Xcode ed eseguire l'applicazione. Quando viene visualizzata la visualizzazione Raccolta, l'applicazione si arresta momentaneamente in modo anomalo con un SIGABRT
errore (come illustrato nell'output dell'applicazione in Visual Studio per Mac) perché PersonModel
non espone una proprietà con la chiave Title
:
Se si scorre fino alla parte superiore dell'errore nell'output dell'applicazione, è possibile visualizzare la chiave per risolvere il problema:
Questa riga indica che la chiave Title
non esiste nell'oggetto a cui si sta eseguendo l'associazione. Se si modifica nuovamente l'associazione Name
in Interface Builder, salvare, sincronizzare, ricompilare ed eseguire, l'applicazione verrà eseguita come previsto senza problemi.
Riepilogo
Questo articolo ha esaminato in dettaglio l'uso del data binding e della codifica chiave-valore in un'applicazione Xamarin.Mac. In primo luogo, ha esaminato l'esposizione di una classe C# a Objective-C usando la codifica chiave-valore (KVC) e l'osservazione chiave-valore (KVO). Successivamente, ha illustrato come usare una classe conforme KVO e Data Bind it agli elementi dell'interfaccia utente in Interface Builder di Xcode. Infine, ha mostrato un data binding complesso usando controller di matrice e controller albero.
Collegamenti correlati
- Hello, Mac
- Controlli standard
- Viste tabella
- Visualizzazioni struttura
- Visualizzazioni raccolta
- Guida alla programmazione della codifica chiave-valore
- Introduzione alla Guida alla programmazione dell'osservazione chiave-valore
- Introduzione agli argomenti di programmazione delle associazioni Cocoa
- Introduzione alle associazioni Cocoa
- NSCollectionView
- Linee guida dell'interfaccia umana macOS