Vinculação de dados e codificação de chave-valor no Xamarin.Mac
Este artigo aborda o uso da codificação de chave-valor e da observação de valor-chave para permitir a vinculação de dados a elementos da interface do usuário no Construtor de Interfaces do Xcode.
Visão geral
Ao trabalhar com C# e .NET em um aplicativo Xamarin.Mac, você tem acesso às mesmas técnicas de codificação de chave-valor e vinculação de dados que um desenvolvedor que trabalha no Objective-C Xcode faz. Como o Xamarin.Mac se integra diretamente ao Xcode, você pode usar o Construtor de Interfaces do Xcode para Vincular Dados com elementos da interface do usuário em vez de escrever código.
Usando técnicas de codificação de chave-valor e vinculação de dados em seu aplicativo Xamarin.Mac, você pode diminuir consideravelmente a quantidade de código que precisa escrever e manter para preencher e trabalhar com elementos da interface do usuário. Você também tem o benefício de desacoplar ainda mais seus dados de suporte (Modelo de Dados) da Interface do Usuário front-end (Model-View-Controller), levando a um design de aplicativo mais fácil de manter e mais flexível.
Neste artigo, abordaremos os conceitos básicos de como trabalhar com codificação de chave-valor e vinculação de dados em um aplicativo Xamarin.Mac. É altamente recomendável que você trabalhe primeiro no artigo Olá, Mac, especificamente nas seções Introdução ao Xcode e ao Construtor de Interface e Saídas e Ações, pois ele aborda os principais conceitos e técnicas que usaremos neste artigo.
Você pode querer dar uma olhada na seção Expondo classes C# / métodos para Objective-Cdo documento Xamarin.Mac Internals também, ele explica os Register
atributos e Export
usados para conectar suas classes C# a Objective-C objetos e elementos da interface do usuário.
O que é codificação chave-valor
A codificação de chave-valor (KVC) é um mecanismo para acessar as propriedades de um objeto indiretamente, usando chaves (cadeias de caracteres especialmente formatadas) para identificar propriedades em vez de acessá-las por meio de variáveis de instância ou métodos de acessador (get/set
). Ao implementar acessadores compatíveis com codificação de chave-valor em seu aplicativo Xamarin.Mac, você obtém acesso a outros recursos do macOS (anteriormente conhecido como OS X), como observação de chave-valor (KVO), vinculação de dados, dados principais, ligações de cacau e scriptabilidade.
Usando técnicas de codificação de chave-valor e vinculação de dados em seu aplicativo Xamarin.Mac, você pode diminuir consideravelmente a quantidade de código que precisa escrever e manter para preencher e trabalhar com elementos da interface do usuário. Você também tem o benefício de desacoplar ainda mais seus dados de suporte (Modelo de Dados) da Interface do Usuário front-end (Model-View-Controller), levando a um design de aplicativo mais fácil de manter e mais flexível.
Por exemplo, vamos examinar a seguinte definição de classe de um objeto compatível com 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 ()
{
}
}
}
Primeiro, o [Register("PersonModel")]
atributo registra a classe e a expõe a Objective-C. Em seguida, a classe precisa herdar de NSObject
(ou uma subclasse que herda de NSObject
), isso adiciona vários métodos base que permitem que a classe seja compatível com KVC. Em seguida, o [Export("Name")]
atributo expõe a Name
propriedade e define o valor Key que será usado posteriormente para acessar a propriedade por meio das técnicas KVC e KVO.
Finalmente, para poder ser Key-Value Observed alterações no valor da propriedade, o acessador deve encapsular as alterações em seu valor em WillChangeValue
e DidChangeValue
chamadas de método (especificando a mesma chave que o Export
atributo). Por exemplo:
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
Essa etapa é muito importante para a vinculação de dados no Construtor de Interface do Xcode (como veremos mais adiante neste artigo).
Para obter mais informações, consulte o Guia de Programação de Codificação de Chave-Valor da Apple.
Chaves e caminhos-chave
Uma chave é uma cadeia de caracteres que identifica uma propriedade específica de um objeto. Normalmente, uma chave corresponde ao nome de um método acessador em um objeto compatível com codificação chave-valor. As chaves devem usar codificação ASCII, geralmente começam com uma letra minúscula e não podem conter espaço em branco. Assim, dado o exemplo acima, Name
seria um Valor Chave da Name
propriedade da PersonModel
classe. A chave e o nome do imóvel que eles expõem não precisam ser os mesmos, mas na maioria dos casos são.
Um Caminho de Chave é uma cadeia de caracteres de Chaves separadas por pontos usada para especificar uma hierarquia de propriedades de objeto a serem percorridas. A propriedade da primeira chave na sequência é relativa ao receptor, e cada chave subsequente é avaliada em relação ao valor da propriedade anterior. Da mesma forma, você usa a notação de ponto para percorrer um objeto e suas propriedades em uma classe C#.
Por exemplo, se você expandiu a classe e adicionou Child
a PersonModel
propriedade:
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 ()
{
}
}
}
O Caminho da Chave para o nome da criança seria self.Child.Name
ou simplesmente Child.Name
(com base em como o Valor da Chave estava sendo usado).
Obtendo valores usando codificação chave-valor
O ValueForKey
método retorna o valor para a chave especificada (como um NSString
), relativo à instância da classe KVC que recebe a solicitação. Por exemplo, se Person
for uma instância da PersonModel
classe definida acima:
// Read value
var name = Person.ValueForKey (new NSString("Name"));
Isso retornaria o valor da Name
propriedade para essa instância de PersonModel
.
Definindo valores usando codificação chave-valor
Da mesma forma, o SetValueForKey
define o valor para a chave especificada (como um NSString
), relativo à instância da classe KVC que recebe a solicitação. Então, novamente, usando uma instância da PersonModel
classe, como mostrado abaixo:
// Write value
Person.SetValueForKey(new NSString("Jane Doe"), new NSString("Name"));
Alteraria o Name
valor da propriedade para Jane Doe
.
Observando mudanças de valor
Usando a observação de chave-valor (KVO), você pode anexar um observador a uma chave específica de uma classe compatível com KVC e ser notificado sempre que o valor dessa chave for modificado (usando técnicas KVC ou acessando diretamente a propriedade dada no código C#). Por exemplo:
// Watch for the name value changing
Person.AddObserver ("Name", NSKeyValueObservingOptions.New, (sender) => {
// Inform caller of selection change
Console.WriteLine("New Name: {0}", Person.Name)
});
Agora, sempre que a Name
propriedade da Person
instância da PersonModel
classe é modificada, o novo valor é gravado no console.
Para obter mais informações, consulte o Guia de Programação de Observação de Valor-Chave da Apple.
Vinculação de dados
As seções a seguir mostrarão como você pode usar uma codificação de chave-valor e uma classe compatível de observação de chave-valor para vincular dados a elementos da interface do usuário no Construtor de Interface do Xcode, em vez de ler e gravar valores usando código C#. Dessa forma, você separa seu Modelo de Dados das exibições que são usadas para exibi-los, tornando o aplicativo Xamarin.Mac mais flexível e fácil de manter. Você também diminui muito a quantidade de código que precisa ser gravado.
Definindo seu modelo de dados
Antes de poder vincular dados a um elemento de interface do usuário no Construtor de Interfaces, você deve ter uma classe compatível com KVC/KVO definida em seu aplicativo Xamarin.Mac para atuar como o Modelo de Dados para a associação. O Modelo de Dados fornece todos os dados que serão exibidos na Interface do Usuário e recebe quaisquer modificações nos dados que o usuário faz na interface do usuário durante a execução do aplicativo.
Por exemplo, se você estivesse escrevendo um aplicativo que gerenciava um grupo de funcionários, poderia usar a seguinte classe para definir o Modelo de Dados:
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
}
}
A maioria dos recursos dessa classe foi abordada na seção O que é codificação de chave-valor acima. No entanto, vamos examinar alguns elementos específicos e algumas adições que foram feitas para permitir que essa classe atue como um Modelo de Dados para Controladores de Matriz e Controladores de Árvore (que usaremos posteriormente para Exibições de Árvore de Vinculação de Dados, Exibições de Estrutura de Tópicos e Exibições de Coleção).
Primeiro, como um funcionário pode ser um gerente, usamos um NSArray
(especificamente um NSMutableArray
para que os valores possam ser modificados) para permitir que os funcionários que eles gerenciaram sejam anexados a eles:
private NSMutableArray _people = new NSMutableArray();
...
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
Duas coisas a observar aqui:
- Usamos uma
NSMutableArray
matriz ou coleção C# em vez de uma padrão, pois esse é um requisito para a Vinculação de Dados a controles do AppKit, como Exibições de Tabela, Exibições de Estrutura de Tópicos e Coleções. - Expusemos a matriz de funcionários convertendo-a em um
NSArray
para fins de vinculação de dados e alteramos seu nome formatado em C#,People
, para um que a vinculação de dados espera,personModelArray
no formato {class_name}Array (observe que o primeiro caractere foi tornado minúsculo).
Em seguida, precisamos adicionar alguns métodos públicos de nome especial para suportar Controladores de Array e Controladores de Árvore:
[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");
}
Eles permitem que os controladores solicitem e modifiquem os dados que eles exibem. Como o exposto NSArray
acima, eles têm uma convenção de nomenclatura muito específica (que difere das convenções de nomenclatura C# típicas):
addObject:
- Adiciona um objeto à matriz.insertObject:in{class_name}ArrayAtIndex:
- Onde{class_name}
está o nome da sua turma. Esse método insere um objeto na matriz em um determinado índice.removeObjectFrom{class_name}ArrayAtIndex:
- Onde{class_name}
está o nome da sua turma. Esse método remove o objeto na matriz em um determinado índice.set{class_name}Array:
- Onde{class_name}
está o nome da sua turma. Este método permite que você substitua o transporte existente por um novo.
Dentro desses métodos, encapsulamos as alterações na WillChangeValue
matriz e DidChangeValue
as mensagens para conformidade com o KVO.
Finalmente, como a Icon
propriedade depende do valor da isManager
propriedade, as isManager
alterações na propriedade podem não ser refletidas nos elementos da interface do usuário vinculados a dados (durante o Icon
KVO):
[Export("Icon")]
public NSImage Icon {
get {
if (isManager) {
return NSImage.ImageNamed ("group.png");
} else {
return NSImage.ImageNamed ("user.png");
}
}
}
Para corrigir isso, usamos o seguinte código:
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
Observe que, além de sua própria Chave, o isManager
acessador também está enviando as WillChangeValue
mensagens e DidChangeValue
para a Icon
Chave para que ele veja a alteração também.
Usaremos o PersonModel
Modelo de Dados durante o restante deste artigo.
Vinculação de dados simples
Com nosso Modelo de Dados definido, vejamos um exemplo simples de vinculação de dados no Construtor de Interfaces do Xcode. Por exemplo, vamos adicionar um formulário ao nosso aplicativo Xamarin.Mac que pode ser usado para editar o PersonModel
que definimos acima. Adicionaremos alguns campos de texto e uma caixa de seleção para exibir e editar as propriedades do nosso modelo.
Primeiro, vamos adicionar um novo View Controller ao nosso arquivo Main.storyboard no Interface Builder e nomear sua classeSimpleViewController
:
Em seguida, retorne ao Visual Studio para Mac, edite o arquivo de SimpleViewController.cs (que foi adicionado automaticamente ao nosso projeto) e exponha uma instância do PersonModel
que vincularemos nossos dados ao formulário. Adicione os códigos a seguir:
private PersonModel _person = new PersonModel();
...
[Export("Person")]
public PersonModel Person {
get {return _person; }
set {
WillChangeValue ("Person");
_person = value;
DidChangeValue ("Person");
}
}
Em seguida, quando a exibição for carregada, vamos criar uma instância nossa PersonModel
e preenchê-la com este código:
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;
}
Agora precisamos criar nosso formulário, clique duas vezes no arquivo Main.storyboard para abri-lo para edição no Construtor de Interfaces. Esquematize o formulário para ter a seguinte aparência:
Para vincular o formulário ao PersonModel
formulário que expusemos por meio da chave, faça o Person
seguinte:
Selecione o Campo de Texto Nome do Funcionário e alterne para o Inspetor de Ligações.
Marque a caixa Vincular a e selecione Controlador de Exibição Simples na lista suspensa. Em seguida, insira
self.Person.Name
para o Caminho da chave:Selecione o Campo de texto de ocupação, marque a caixa Vincular a e selecione Controlador de exibição simples na lista suspensa. Em seguida, insira
self.Person.Occupation
para o Caminho da chave:Marque a caixa de seleção Funcionário é um gerente , marque a caixa Vincular a e selecione Controlador de exibição simples na lista suspensa. Em seguida, insira
self.Person.isManager
para o Caminho da chave:Selecione o campo Número de Funcionários Texto Gerenciado e marque a caixa Vincular a e selecione Controlador de Exibição Simples na lista suspensa. Em seguida, insira
self.Person.NumberOfEmployees
para o Caminho da chave:Se o funcionário não for um gerente, desejamos ocultar o Rótulo e o Campo de Texto Número de Funcionários Gerenciados.
Selecione o Rótulo Número de Funcionários Gerenciados , expanda o turndown Oculto e marque a caixa Vincular a e selecione Controlador de Exibição Simples na lista suspensa. Em seguida, insira
self.Person.isManager
para o Caminho da chave:Selecione
NSNegateBoolean
na lista suspensa Value Transformer :Isso informa à vinculação de dados que o rótulo ficará oculto se o valor da
isManager
propriedade forfalse
.Repita as etapas 7 e 8 para o campo de texto Número de funcionários gerenciados .
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Se você executar o aplicativo, os valores da Person
propriedade preencherão automaticamente nosso formulário:
Quaisquer alterações feitas pelos usuários no formulário serão gravadas de volta Person
na propriedade no View Controller. Por exemplo, desmarcar Funcionário é um Gerente atualiza a Person
instância de nosso PersonModel
e o Número de Funcionários Gerenciado Rótulo e Campo de Texto ficam ocultos automaticamente (por meio de associação de dados):
Vinculação de dados do modo de exibição de tabela
Agora que temos os conceitos básicos de vinculação de dados fora do caminho, vamos examinar uma tarefa de vinculação de dados mais complexa usando um Controlador de Matriz e vinculação de dados a uma Exibição de Tabela . Para obter mais informações sobre como trabalhar com Exibições de Tabela, consulte nossa documentação de Exibições de Tabela .
Primeiro, vamos adicionar um novo View Controller ao nosso arquivo Main.storyboard no Interface Builder e nomear sua classeTableViewController
:
Em seguida, vamos editar o arquivo TableViewController.cs (que foi adicionado automaticamente ao nosso projeto) e expor uma matriz (NSArray
) de PersonModel
classes às quais vincularemos nosso formulário. Adicione os códigos a seguir:
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");
}
Assim como fizemos na PersonModel
classe acima na seção Definindo seu Modelo de Dados, expomos quatro métodos públicos especialmente nomeados para que o Controlador de Matriz e os dados de leitura e gravação de nossa coleção de PersonModels
.
Em seguida, quando a exibição for carregada, precisamos preencher nossa matriz com este código:
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"));
}
Agora precisamos criar nossa Exibição de Tabela, clique duas vezes no arquivo Main.storyboard para abri-lo para edição no Construtor de Interfaces. Esquematize a tabela para ter a seguinte aparência:
Precisamos adicionar um controlador de matriz para fornecer dados vinculados à nossa tabela, faça o seguinte:
Arraste um controlador de matriz do Inspetor de biblioteca para o Editor de interface:
Selecione Controlador de Matriz na Hierarquia de Interface e alterne para o Inspetor de Atributos:
Digite
PersonModel
o Nome da classe, clique no botão de adição e adicione três chaves. Nomeie-osName
eOccupation
isManager
:Isso informa ao Controlador de Matriz do que ele está gerenciando uma matriz e quais propriedades ele deve expor (via Chaves).
Alterne para o Inspetor de Ligações e, em Matriz de Conteúdo , selecione Vincular a e Controlador de Exibição de Tabela. Insira um caminho de chave de modelo de
self.personModelArray
:Isso vincula o Controlador de Matriz à matriz que expomos em nosso Controlador de
PersonModels
Exibição.
Agora precisamos vincular nossa Exibição de Tabela ao Controlador de Matriz, faça o seguinte:
Selecione o Modo de Exibição de Tabela e o Inspetor de Vinculação:
Na lista de ativação Conteúdo da Tabela, selecione Vincular a e Controlador de Matriz. Insira
arrangedObjects
o campo Chave do controlador:Selecione a Célula de Exibição de Tabela na coluna Funcionário . No Inspetor de Ligações, sob o botão de ativação Valor, selecione Vincular a e Modo de Exibição de Célula da Tabela. Digite
objectValue.Name
para o caminho da chave do modelo:objectValue
é a correntePersonModel
na matriz que está sendo gerenciada pelo Controlador de Matriz.Selecione a Célula de Exibição de Tabela na coluna Ocupação . No Inspetor de Ligações, sob o botão de ativação Valor, selecione Vincular a e Modo de Exibição de Célula da Tabela. Digite
objectValue.Occupation
para o caminho da chave do modelo:Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Se executarmos o aplicativo, a tabela será preenchida com nossa matriz de PersonModels
:
Vinculação de dados do modo de exibição de estrutura de tópicos
a vinculação de dados em um Modo de Exibição de Estrutura de Tópicos é muito semelhante à vinculação em um Modo de Exibição de Tabela. A principal diferença é que usaremos um Controlador de Árvore em vez de um Controlador de Matriz para fornecer os dados vinculados à Exibição de Estrutura de Tópicos. Para obter mais informações sobre como trabalhar com Modos de Exibição de Estrutura de Tópicos, consulte nossa documentação de Modos de Exibição de Estrutura de Tópicos .
Primeiro, vamos adicionar um novo View Controller ao nosso arquivo Main.storyboard no Interface Builder e nomear sua classeOutlineViewController
:
Em seguida, vamos editar o arquivo OutlineViewController.cs (que foi adicionado automaticamente ao nosso projeto) e expor uma matriz (NSArray
) de PersonModel
classes às quais vincularemos nossos dados. Adicione os códigos a seguir:
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");
}
Assim como fizemos na PersonModel
classe acima na seção Definindo seu Modelo de Dados, expomos quatro métodos públicos especialmente nomeados para que o Controlador de Árvore e os dados de leitura e gravação de nossa coleção de PersonModels
.
Em seguida, quando a exibição for carregada, precisamos preencher nossa matriz com este código:
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);
}
Agora precisamos criar nossa Exibição de Estrutura de Tópicos, clique duas vezes no arquivo Main.storyboard para abri-lo para edição no Construtor de Interfaces. Esquematize a tabela para ter a seguinte aparência:
Precisamos adicionar um controlador de árvore para fornecer dados vinculados ao nosso esboço, faça o seguinte:
Arraste um controlador de árvore do Inspetor de biblioteca para o Editor de interface:
Selecione Controlador de árvore na hierarquia de interface e alterne para o Inspetor de atributos:
Digite
PersonModel
o Nome da classe, clique no botão de adição e adicione três chaves. Nomeie-osName
eOccupation
isManager
:Isso informa ao Controlador de Árvore do que ele está gerenciando uma matriz e quais propriedades ele deve expor (via Chaves).
Na seção Controlador de Árvore , insira
personModelArray
para Filhos, entreNumberOfEmployees
em Contagem e entreisEmployee
em Folha:Isso informa ao Controlador de Árvore onde encontrar qualquer nó filho, quantos nós filho existem e se o nó atual tem nós filho.
Alterne para o Inspetor de Ligações e, em Matriz de Conteúdo , selecione Vincular ao Proprietário do Arquivo. Insira um caminho de chave de modelo de
self.personModelArray
:Isso vincula o Controlador de Árvore à matriz que expomos em nosso Controlador de
PersonModels
Exibição.
Agora precisamos vincular nossa Exibição de Estrutura de Tópicos ao Controlador de Árvore, faça o seguinte:
Selecione o Modo de Exibição de Estrutura de Tópicos e, no Inspetor de Vinculação, selecione :
No turndown Conteúdo da Exibição de Estrutura de Tópicos, selecione Vincular a e Controlador de Árvore. Insira
arrangedObjects
o campo Chave do controlador:Selecione a Célula de Exibição de Tabela na coluna Funcionário . No Inspetor de Ligações, sob o botão de ativação Valor, selecione Vincular a e Modo de Exibição de Célula da Tabela. Digite
objectValue.Name
para o caminho da chave do modelo:objectValue
é a correntePersonModel
na matriz que está sendo gerenciada pelo Controlador de Árvore.Selecione a Célula de Exibição de Tabela na coluna Ocupação . No Inspetor de Ligações, sob o botão de ativação Valor, selecione Vincular a e Modo de Exibição de Célula da Tabela. Digite
objectValue.Occupation
para o caminho da chave do modelo:Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Se executarmos o aplicativo, a estrutura de tópicos será preenchida com nossa matriz de PersonModels
:
Vinculação de dados do modo de exibição de coleta
A vinculação de dados com um Modo de Exibição de Coleta é muito semelhante à vinculação com um Modo de Exibição de Tabela, pois um Controlador de Matriz é usado para fornecer dados para a coleção. Como o modo de exibição de coleção não tem um formato de exibição predefinido, é necessário mais trabalho para fornecer feedback de interação do usuário e acompanhar a seleção do usuário.
Importante
Devido a um problema no Xcode 7 e no macOS 10.11 (e superiores), as Visualizações de coleção não podem ser usadas dentro de arquivos de Storyboard (.storyboard). Como resultado, você precisará continuar a usar arquivos .xib para definir suas Visualizações de Coleção para seus aplicativos Xamarin.Mac. Consulte nossa documentação de Visualizações de coleção para obter mais informações.
Depurando falhas nativas
Cometer um erro em suas ligações de dados pode resultar em uma falha nativa no código não gerenciado e fazer com que seu aplicativo Xamarin.Mac falhe completamente com um SIGABRT
erro:
Normalmente, há quatro causas principais para falhas nativas durante a vinculação de dados:
- Seu Modelo de Dados não herda de
NSObject
ou uma subclasse deNSObject
. - Você não expôs sua propriedade ao Objective-C uso do
[Export("key-name")]
atributo. - Você não encapsulava as alterações no valor do acessador em
WillChangeValue
eDidChangeValue
chamadas de método (especificando a mesma chave que oExport
atributo). - Você tem uma chave errada ou digitada incorretamente no Inspetor de vinculação no Construtor de Interfaces.
Decodificando uma falha
Vamos causar uma falha nativa em nossa vinculação de dados para que possamos mostrar como localizá-la e corrigi-la. No Construtor de Interfaces, vamos alterar nossa associação do primeiro Rótulo no exemplo de Modo de Exibição de Coleção de Name
para Title
:
Vamos salvar a alteração, voltar para o Visual Studio para Mac para sincronizar com o Xcode e executar nosso aplicativo. Quando o Modo de Exibição de Coleção é exibido, o aplicativo falhará momentaneamente com um SIGABRT
erro (conforme mostrado na Saída do Aplicativo no Visual Studio para Mac), uma vez que o PersonModel
não expõe uma propriedade com a Chave Title
:
Se rolarmos até o topo do erro na saída do aplicativo, podemos ver a chave para resolver o problema:
Essa linha está nos dizendo que a chave Title
não existe no objeto ao qual estamos vinculando. Se alterarmos a vinculação de volta para Name
no Construtor de Interfaces, salvar, sincronizar, reconstruir e executar, o aplicativo será executado conforme o esperado sem problemas.
Resumo
Este artigo deu uma olhada detalhada no trabalho com vinculação de dados e codificação de chave-valor em um aplicativo Xamarin.Mac. Primeiro, ele analisou a exposição de uma classe C# usando Objective-C codificação de chave-valor (KVC) e observação de valor-chave (KVO). Em seguida, ele mostrou como usar uma classe compatível com KVO e vinculá-la a elementos da interface do usuário no Construtor de Interface do Xcode. Finalmente, mostrou a complexa vinculação de dados usando Controladores de Matriz e Controladores de Árvore.
Links relacionados
- Hello, Mac
- Controles padrão
- Exibições de tabela
- Modos de exibição de estrutura de tópicos
- Visualizações de coleção
- Guia de Programação de Codificação de Chave-Valor
- Introdução ao Guia de Programação de Observação de Valor-Chave
- Introdução aos tópicos de programação de ligações de cacau
- Introdução à Referência de Ligações de Cacau
- NSCollectionView
- Diretrizes de Interface Humana do macOS