Exibições de tabela no Xamarin.Mac
Este artigo aborda o trabalho com modos de exibição de tabela em um aplicativo Xamarin.Mac. Ele descreve a criação de exibições de tabela no Xcode e no Construtor de Interfaces e a interação com eles no código.
Ao trabalhar com C# e .NET em um aplicativo Xamarin.Mac, você tem acesso às mesmas Exibições de Tabela que um desenvolvedor que trabalha e Objective-Co Xcode . Como o Xamarin.Mac se integra diretamente ao Xcode, você pode usar o Construtor de Interfaces do Xcode para criar e manter suas Exibições de Tabela (ou, opcionalmente, criá-las diretamente no código C#).
Um Modo de Exibição de Tabela exibe dados em um formato tabular contendo uma ou mais colunas de informações em várias linhas. Com base no tipo de Modo de Exibição de Tabela que está sendo criado, o usuário pode classificar por coluna, reorganizar colunas, adicionar colunas, remover colunas ou editar os dados contidos na tabela.
Neste artigo, abordaremos os conceitos básicos de como trabalhar com Exibições de Tabela 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-C do documento Xamarin.Mac Internals também, ele explica os Register
comandos e Export
usados para conectar suas classes C# a Objective-C objetos e elementos da interface do usuário.
Introdução às Exibições de Tabela
Um Modo de Exibição de Tabela exibe dados em um formato tabular contendo uma ou mais colunas de informações em várias linhas. As Visualizações de Tabela são exibidas dentro das Visualizações de Rolagem (NSScrollView
) e, a partir do macOS 10.7, você pode usar qualquer NSView
uma em vez de Células (NSCell
) para exibir linhas e colunas. Dito isso, você ainda pode usar NSCell
, no entanto, você normalmente subclasse NSTableCellView
e criar suas linhas e colunas personalizadas.
Um Modo de Exibição de Tabela não armazena seus próprios dados, em vez disso, ele depende de uma Fonte de Dados (NSTableViewDataSource
) para fornecer as linhas e colunas necessárias, conforme necessário.
O comportamento de um Modo de Exibição de Tabela pode ser personalizado fornecendo uma subclasse do Delegado do Modo de Exibição de Tabela (NSTableViewDelegate
) para oferecer suporte ao gerenciamento de colunas de tabela, tipo para selecionar funcionalidade, seleção e edição de linhas, controle personalizado e modos de exibição personalizados para colunas e linhas individuais.
Ao criar Exibições de Tabela, a Apple sugere o seguinte:
- Permita que o usuário classifique a tabela clicando em Cabeçalhos de Coluna.
- Crie cabeçalhos de coluna que são substantivos ou frases nominais curtas que descrevem os dados que estão sendo mostrados nessa coluna.
Para obter mais informações, consulte a seção Visualizações de conteúdo das Diretrizes de interface humana do OS X da Apple.
Criando e mantendo exibições de tabela no Xcode
Ao criar um novo aplicativo Xamarin.Mac Cocoa, você obtém uma janela padrão em branco por padrão. Essa janela é definida em um .storyboard
arquivo incluído automaticamente no projeto. Para editar o design do Windows, no Gerenciador de Soluções, clique duas vezes no Main.storyboard
arquivo:
Isso abrirá o design da janela no Construtor de Interfaces do Xcode:
Digite table
na caixa de pesquisa do Inspetor de Biblioteca para facilitar a localização dos controles de Exibição de Tabela:
Arraste uma Vista de Tabela para o Controlador de Vista no Editor de Interface, faça-a preencher a área de conteúdo do Controlador de Vista e defina-a para onde diminui e cresce com a janela no Editor de Restrições:
Selecione o Modo de Exibição de Tabela na Hierarquia de Interface e as seguintes propriedades estão disponíveis no Inspetor de Atributos:
- Modo de Conteúdo - Permite que você use Modos de Exibição (
NSView
) ou Células (NSCell
) para exibir os dados nas linhas e colunas. A partir do macOS 10.7, você deve usar Visualizações. - Flutua Agrupar Linhas - Se
true
, o Modo de Exibição de Tabela desenhará células agrupadas como se estivessem flutuando. - Colunas - Define o número de colunas exibidas.
- Cabeçalhos - Se
true
, as colunas terão Cabeçalhos. - Reordenação - Se
true
, o usuário poderá arrastar reordenar as colunas na tabela. - Redimensionamento - Se
true
, o usuário poderá arrastar cabeçalhos de coluna para redimensionar colunas. - Dimensionamento de Colunas - Controla como a tabela dimensionará automaticamente as colunas.
- Realce - Controla o tipo de realce que a tabela usa quando uma célula é selecionada.
- Linhas alternativas - Se
true
, alguma outra linha terá uma cor de fundo diferente. - Grade Horizontal - Seleciona o tipo de borda desenhada entre as células horizontalmente.
- Grade Vertical - Seleciona o tipo de borda desenhada entre as células verticalmente.
- Cor da grade - Define a cor da borda da célula.
- Plano de fundo - Define a cor do plano de fundo da célula.
- Seleção - Permite controlar como o usuário pode selecionar células na tabela como:
- Múltiplos - Se
true
, o usuário pode selecionar várias linhas e colunas. - Coluna - Se
true
,o usuário pode selecionar colunas. - Tipo Selecionar - Se
true
, o usuário pode digitar um caractere para selecionar uma linha. - Vazio - Se
true
, o usuário não for obrigado a selecionar uma linha ou coluna, a tabela não permitirá nenhuma seleção.
- Múltiplos - Se
- Salvamento automático - O nome no qual o formato das tabelas é salvo automaticamente.
- Informações da coluna - Se
true
, a ordem e a largura das colunas serão salvas automaticamente. - Quebras de linha - Selecione como a célula lida com quebras de linha.
- Trunca a Última Linha Visível - Se
true
, a célula será truncada nos dados não pode caber dentro de seus limites.
Importante
A menos que você esteja mantendo um aplicativo Xamarin.Mac herdado, NSView
as Exibições de Tabela baseadas devem ser usadas sobre as Exibições de Tabela baseadas em NSCell
Tabela. NSCell
é considerado legado e pode não ser suportado daqui para frente.
Selecione uma Coluna de Tabela na Hierarquia de Interface e as seguintes propriedades estão disponíveis no Inspetor de Atributos:
- Título - Define o título da coluna.
- Alinhamento - Defina o alinhamento do texto dentro das células.
- Fonte do Título - Seleciona a fonte do texto do cabeçalho da célula.
- Chave de classificação - É a chave usada para classificar dados na coluna. Deixe em branco se o usuário não puder classificar essa coluna.
- Seletor - É a Ação usada para executar a classificação. Deixe em branco se o usuário não puder classificar essa coluna.
- Ordem - É a ordem de classificação dos dados das colunas.
- Redimensionamento - Seleciona o tipo de redimensionamento para a coluna.
- Editável - Se
true
, o usuário pode editar células em uma tabela baseada em célula. - Oculto - Se
true
, a coluna está oculta.
Você também pode redimensionar a coluna arrastando sua alça (verticalmente centralizada no lado direito da coluna) para a esquerda ou para a direita.
Vamos selecionar cada coluna em nossa Exibição de tabela e dar à primeira coluna um título de Product
e a segunda Details
.
Selecione uma Exibição de Célula de Tabela (NSTableViewCell
) na Hierarquia de Interface e as seguintes propriedades estão disponíveis no Inspetor de Atributos:
Essas são todas as propriedades de um Modo de Exibição padrão. Você também tem a opção de redimensionar as linhas para esta coluna aqui.
Selecione uma Célula de Exibição de Tabela (por padrão, isso é um NSTextField
) na Hierarquia de Interface e as seguintes propriedades estão disponíveis no Inspetor de Atributos:
Você terá todas as propriedades de um campo de texto padrão para definir aqui. Por padrão, um Campo de Texto padrão é usado para exibir dados de uma célula em uma coluna.
Selecione uma Exibição de Célula de Tabela (NSTableFieldCell
) na Hierarquia de Interface e as seguintes propriedades estão disponíveis no Inspetor de Atributos:
As configurações mais importantes aqui são:
- Layout - Selecione como as células nesta coluna são dispostas.
- Usa o modo de linha única - Se
true
, a célula está limitada a uma única linha. - First Runtime Layout Width - Se
true
, a célula preferirá a largura definida para ela (manual ou automaticamente) quando for exibida na primeira vez que o aplicativo for executado. - Ação - Controla quando a Ação de Edição é enviada para a célula.
- Comportamento - Define se uma célula é selecionável ou editável.
- Rich Text - Se
true
, a célula pode exibir texto formatado e estilizado. - Desfazer - Se
true
, a célula assume a responsabilidade pelo seu comportamento de desfazer.
Selecione a Exibição de Célula da Tabela (NSTableFieldCell
) na parte inferior de uma Coluna da Tabela na Hierarquia de Interface:
Isso permite que você edite o Modo de Exibição de Célula da Tabela usado como o Padrão base para todas as células criadas para a coluna especificada.
Adicionando ações e saídas
Assim como qualquer outro controle de interface do usuário do Cocoa, precisamos expor nossa Exibição de Tabela e suas colunas e células ao código C# usando Ações e Saídas (com base na funcionalidade necessária).
O processo é o mesmo para qualquer elemento de Exibição de Tabela que desejamos expor:
Alterne para o Editor Assistente e verifique se o
ViewController.h
arquivo está selecionado:Selecione a Exibição de Tabela na Hierarquia de Interface, clique com a tecla Control pressionada e arraste para o
ViewController.h
arquivo.Crie uma saída para o modo de exibição de tabela chamado
ProductTable
:Crie saídas para as colunas de tabelas, bem chamadas
ProductColumn
eDetailsColumn
:Salve as alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Em seguida, escreveremos o código para exibir alguns dados para a tabela quando o aplicativo for executado.
Preenchendo o modo de exibição de tabela
Com nossa Exibição de Tabela projetada no Construtor de Interface e exposta por meio de um Outlet, em seguida, precisamos criar o código C# para preenchê-lo.
Primeiro, vamos criar uma nova Product
classe para armazenar as informações das linhas individuais. No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione General>Empty Class, digite Product
para o Nome e clique no botão Novo:
Faça com que o Product.cs
arquivo tenha a seguinte aparência:
using System;
namespace MacTables
{
public class Product
{
#region Computed Properties
public string Title { get; set;} = "";
public string Description { get; set;} = "";
#endregion
#region Constructors
public Product ()
{
}
public Product (string title, string description)
{
this.Title = title;
this.Description = description;
}
#endregion
}
}
Em seguida, precisamos criar uma subclasse de NSTableDataSource
para fornecer os dados para nossa tabela conforme solicitado. No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione General>Empty Class, digite ProductTableDataSource
para o Nome e clique no botão Novo.
Edite o ProductTableDataSource.cs
arquivo e faça com que ele tenha a seguinte aparência:
using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;
namespace MacTables
{
public class ProductTableDataSource : NSTableViewDataSource
{
#region Public Variables
public List<Product> Products = new List<Product>();
#endregion
#region Constructors
public ProductTableDataSource ()
{
}
#endregion
#region Override Methods
public override nint GetRowCount (NSTableView tableView)
{
return Products.Count;
}
#endregion
}
}
Essa classe tem armazenamento para os itens do Modo de Exibição de Tabela e substitui o GetRowCount
para retornar o número de linhas na tabela.
Finalmente, precisamos criar uma subclasse de NSTableDelegate
para fornecer o comportamento para nossa tabela. No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione General>Empty Class, digite ProductTableDelegate
para o Nome e clique no botão Novo.
Edite o ProductTableDelegate.cs
arquivo e faça com que ele tenha a seguinte aparência:
using System;
using AppKit;
using CoreGraphics;
using Foundation;
using System.Collections;
using System.Collections.Generic;
namespace MacTables
{
public class ProductTableDelegate: NSTableViewDelegate
{
#region Constants
private const string CellIdentifier = "ProdCell";
#endregion
#region Private Variables
private ProductTableDataSource DataSource;
#endregion
#region Constructors
public ProductTableDelegate (ProductTableDataSource datasource)
{
this.DataSource = datasource;
}
#endregion
#region Override Methods
public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
// This pattern allows you reuse existing views when they are no-longer in use.
// If the returned view is null, you instance up a new view
// If a non-null view is returned, you modify it enough to reflect the new data
NSTextField view = (NSTextField)tableView.MakeView (CellIdentifier, this);
if (view == null) {
view = new NSTextField ();
view.Identifier = CellIdentifier;
view.BackgroundColor = NSColor.Clear;
view.Bordered = false;
view.Selectable = false;
view.Editable = false;
}
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
view.StringValue = DataSource.Products [(int)row].Title;
break;
case "Details":
view.StringValue = DataSource.Products [(int)row].Description;
break;
}
return view;
}
#endregion
}
}
Quando criamos uma instância do ProductTableDelegate
, também passamos uma instância do ProductTableDataSource
que fornece os dados para a tabela. O GetViewForItem
método é responsável por retornar uma exibição (dados) para exibir a célula para uma determinada coluna e linha. Se possível, um modo de exibição existente será reutilizado para exibir a célula, se não um novo modo de exibição deve ser criado.
Para preencher a tabela, vamos editar o ViewController.cs
arquivo e fazer com que o AwakeFromNib
método tenha a seguinte aparência:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Create the Product Table Data Source and populate it
var DataSource = new ProductTableDataSource ();
DataSource.Products.Add (new Product ("Xamarin.iOS", "Allows you to develop native iOS Applications in C#"));
DataSource.Products.Add (new Product ("Xamarin.Android", "Allows you to develop native Android Applications in C#"));
DataSource.Products.Add (new Product ("Xamarin.Mac", "Allows you to develop Mac native Applications in C#"));
// Populate the Product Table
ProductTable.DataSource = DataSource;
ProductTable.Delegate = new ProductTableDelegate (DataSource);
}
Se executarmos o aplicativo, o seguinte será exibido:
Classificação por coluna
Vamos permitir que o usuário classifique os dados na tabela clicando em um Cabeçalho de Coluna. Primeiro, clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces. Selecione a Product
coluna, digite Title
para a Chave de Classificação, compare:
para o Seletor e selecione Ascending
para a Ordem:
Selecione a Details
coluna, digite Description
para a Chave de Classificação, compare:
para o Seletor e selecione Ascending
para a Ordem:
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Agora vamos editar o ProductTableDataSource.cs
arquivo e adicionar os seguintes métodos:
public void Sort(string key, bool ascending) {
// Take action based on key
switch (key) {
case "Title":
if (ascending) {
Products.Sort ((x, y) => x.Title.CompareTo (y.Title));
} else {
Products.Sort ((x, y) => -1 * x.Title.CompareTo (y.Title));
}
break;
case "Description":
if (ascending) {
Products.Sort ((x, y) => x.Description.CompareTo (y.Description));
} else {
Products.Sort ((x, y) => -1 * x.Description.CompareTo (y.Description));
}
break;
}
}
public override void SortDescriptorsChanged (NSTableView tableView, NSSortDescriptor[] oldDescriptors)
{
// Sort the data
if (oldDescriptors.Length > 0) {
// Update sort
Sort (oldDescriptors [0].Key, oldDescriptors [0].Ascending);
} else {
// Grab current descriptors and update sort
NSSortDescriptor[] tbSort = tableView.SortDescriptors;
Sort (tbSort[0].Key, tbSort[0].Ascending);
}
// Refresh table
tableView.ReloadData ();
}
O Sort
método nos permite classificar os dados na Fonte de Dados com base em um determinado Product
campo de classe em ordem crescente ou decrescente. O método substituído SortDescriptorsChanged
será chamado toda vez que o uso clicar em um título de coluna. Será passado o valor de chave que definimos no Construtor de Interface e a ordem de classificação para essa coluna.
Se executarmos o aplicativo e clicarmos nos Cabeçalhos de Coluna, as linhas serão classificadas por essa coluna:
Seleção de linha
Se você quiser permitir que o usuário selecione uma única linha, clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces. Marque a Exibição de Tabela na Hierarquia de Interface e desmarque a caixa de seleção Vários no Inspetor de Atributos:
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Em seguida, edite o ProductTableDelegate.cs
arquivo e adicione o seguinte método:
public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
return true;
}
Isso permitirá que o usuário selecione qualquer linha única no Modo de Exibição de Tabela. Retorne false
para a ShouldSelectRow
linha para qualquer linha que você não deseja que o usuário possa selecionar ou false
para cada linha se você não quiser que o usuário possa selecionar nenhuma linha.
O Modo de Exibição de Tabela (NSTableView
) contém os seguintes métodos para trabalhar com seleção de linha:
DeselectRow(nint)
- Desmarca a linha fornecida na tabela.SelectRow(nint,bool)
- Seleciona a linha dada. Passefalse
para o segundo parâmetro para selecionar apenas uma linha de cada vez.SelectedRow
- Retorna a linha atual selecionada na tabela.IsRowSelected(nint)
- Retornatrue
se a linha fornecida estiver selecionada.
Seleção de várias linhas
Se você quiser permitir que o usuário selecione várias linhas, clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces. Marque a Exibição de Tabela na Hierarquia de Interface e marque a caixa de seleção Vários no Inspetor de Atributos:
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Em seguida, edite o ProductTableDelegate.cs
arquivo e adicione o seguinte método:
public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
return true;
}
Isso permitirá que o usuário selecione qualquer linha única no Modo de Exibição de Tabela. Retorne false
para a ShouldSelectRow
linha para qualquer linha que você não deseja que o usuário possa selecionar ou false
para cada linha se você não quiser que o usuário possa selecionar nenhuma linha.
O Modo de Exibição de Tabela (NSTableView
) contém os seguintes métodos para trabalhar com seleção de linha:
DeselectAll(NSObject)
- Desmarca todas as linhas na tabela. Usethis
para o primeiro parâmetro para enviar o objeto que está fazendo a seleção.DeselectRow(nint)
- Desmarca a linha fornecida na tabela.SelectAll(NSobject)
- Seleciona todas as linhas da tabela. Usethis
para o primeiro parâmetro para enviar o objeto que está fazendo a seleção.SelectRow(nint,bool)
- Seleciona a linha dada. Passefalse
para o segundo parâmetro limpar a seleção e selecione apenas uma única linha, passetrue
para estender a seleção e incluir essa linha.SelectRows(NSIndexSet,bool)
- Seleciona o conjunto de linhas dado. Passefalse
para o segundo parâmetro limpar a seleção e selecione apenas uma dessas linhas, passetrue
para estender a seleção e incluir essas linhas.SelectedRow
- Retorna a linha atual selecionada na tabela.SelectedRows
- Retorna umNSIndexSet
contendo os índices das linhas selecionadas.SelectedRowCount
- Retorna o número de linhas selecionadas.IsRowSelected(nint)
- Retornatrue
se a linha fornecida estiver selecionada.
Digite para selecionar linha
Se você quiser permitir que o usuário digite um caractere com o Modo de Exibição de Tabela selecionado e selecione a primeira linha que tem esse caractere, clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces. Marque a Exibição de Tabela na Hierarquia de Interface e marque a caixa de seleção Seleção de Tipo no Inspetor de Atributos:
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Agora vamos editar o ProductTableDelegate.cs
arquivo e adicionar o seguinte método:
public override nint GetNextTypeSelectMatch (NSTableView tableView, nint startRow, nint endRow, string searchString)
{
nint row = 0;
foreach(Product product in DataSource.Products) {
if (product.Title.Contains(searchString)) return row;
// Increment row counter
++row;
}
// If not found select the first row
return 0;
}
O GetNextTypeSelectMatch
método pega o dado searchString
e retorna a linha do primeiro Product
que tem essa cadeia de caracteres em seu Title
.
Se executarmos o aplicativo e digitarmos um caractere, uma linha será selecionada:
Reordenando colunas
Se você quiser permitir que o usuário arraste colunas de reordenação no Modo de Exibição de Tabela, clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces. Marque a Exibição de Tabela na Hierarquia de Interface e marque a caixa de seleção Reordenar no Inspetor de Atributos:
Se dermos um valor para a propriedade Autosave e verificarmos o campo Informações da Coluna, quaisquer alterações que fizermos no layout da tabela serão salvas automaticamente para nós e restauradas na próxima vez que o aplicativo for executado.
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Agora vamos editar o ProductTableDelegate.cs
arquivo e adicionar o seguinte método:
public override bool ShouldReorder (NSTableView tableView, nint columnIndex, nint newColumnIndex)
{
return true;
}
O ShouldReorder
método deve retornar true
para qualquer coluna que ele deseja permitir que seja arrastada reordenada para o newColumnIndex
, caso contrário, retorne false
;
Se executarmos o aplicativo, podemos arrastar cabeçalhos de coluna para reordenar nossas colunas:
Editando células
Se você quiser permitir que o usuário edite os valores de uma determinada célula, edite o ProductTableDelegate.cs
arquivo e altere o GetViewForItem
método da seguinte maneira:
public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
// This pattern allows you reuse existing views when they are no-longer in use.
// If the returned view is null, you instance up a new view
// If a non-null view is returned, you modify it enough to reflect the new data
NSTextField view = (NSTextField)tableView.MakeView (tableColumn.Title, this);
if (view == null) {
view = new NSTextField ();
view.Identifier = tableColumn.Title;
view.BackgroundColor = NSColor.Clear;
view.Bordered = false;
view.Selectable = false;
view.Editable = true;
view.EditingEnded += (sender, e) => {
// Take action based on type
switch(view.Identifier) {
case "Product":
DataSource.Products [(int)view.Tag].Title = view.StringValue;
break;
case "Details":
DataSource.Products [(int)view.Tag].Description = view.StringValue;
break;
}
};
}
// Tag view
view.Tag = row;
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
view.StringValue = DataSource.Products [(int)row].Title;
break;
case "Details":
view.StringValue = DataSource.Products [(int)row].Description;
break;
}
return view;
}
Agora, se executarmos o aplicativo, o usuário poderá editar as células no Modo de Exibição de Tabela:
Usando imagens em modos de exibição de tabela
Para incluir uma imagem como parte da célula em um NSTableView
, você precisará alterar como os dados são retornados pelo método doGetViewForItem
NSTableViewDelegate's
Modo de Exibição de Tabela para usar um NSTableCellView
em vez do típico NSTextField
. Por exemplo:
public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
// This pattern allows you reuse existing views when they are no-longer in use.
// If the returned view is null, you instance up a new view
// If a non-null view is returned, you modify it enough to reflect the new data
NSTableCellView view = (NSTableCellView)tableView.MakeView (tableColumn.Title, this);
if (view == null) {
view = new NSTableCellView ();
if (tableColumn.Title == "Product") {
view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
view.AddSubview (view.ImageView);
view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
} else {
view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
}
view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
view.AddSubview (view.TextField);
view.Identifier = tableColumn.Title;
view.TextField.BackgroundColor = NSColor.Clear;
view.TextField.Bordered = false;
view.TextField.Selectable = false;
view.TextField.Editable = true;
view.TextField.EditingEnded += (sender, e) => {
// Take action based on type
switch(view.Identifier) {
case "Product":
DataSource.Products [(int)view.TextField.Tag].Title = view.TextField.StringValue;
break;
case "Details":
DataSource.Products [(int)view.TextField.Tag].Description = view.TextField.StringValue;
break;
}
};
}
// Tag view
view.TextField.Tag = row;
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
view.ImageView.Image = NSImage.ImageNamed ("tags.png");
view.TextField.StringValue = DataSource.Products [(int)row].Title;
break;
case "Details":
view.TextField.StringValue = DataSource.Products [(int)row].Description;
break;
}
return view;
}
Para obter mais informações, consulte a seção Usando imagens com exibições de tabela da nossa documentação Trabalhando com imagens .
Adicionando um botão Excluir a uma linha
Com base nos requisitos do seu aplicativo, pode haver ocasiões em que você precise fornecer um botão de ação para cada linha na tabela. Como exemplo disso, vamos expandir o exemplo de Modo de Exibição de Tabela criado acima para incluir um botão Excluir em cada linha.
Primeiro, edite o Main.storyboard
no Construtor de Interfaces do Xcode, selecione a Exibição de Tabela e aumente o número de colunas para três (3). Em seguida, altere o Título da nova coluna para Action
:
Salve as alterações no Storyboard e retorne ao Visual Studio para Mac para sincronizar as alterações.
Em seguida, edite o ViewController.cs
arquivo e adicione o seguinte método público:
public void ReloadTable ()
{
ProductTable.ReloadData ();
}
No mesmo arquivo, modifique a criação do novo Delegado de Exibição de Tabela dentro do método da ViewDidLoad
seguinte maneira:
// Populate the Product Table
ProductTable.DataSource = DataSource;
ProductTable.Delegate = new ProductTableDelegate (this, DataSource);
Agora, edite o ProductTableDelegate.cs
arquivo para incluir uma conexão privada com o View Controller e para usar o controlador como um parâmetro ao criar uma nova instância do delegado:
#region Private Variables
private ProductTableDataSource DataSource;
private ViewController Controller;
#endregion
#region Constructors
public ProductTableDelegate (ViewController controller, ProductTableDataSource datasource)
{
this.Controller = controller;
this.DataSource = datasource;
}
#endregion
Em seguida, adicione o seguinte novo método privado à classe:
private void ConfigureTextField (NSTableCellView view, nint row)
{
// Add to view
view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
view.AddSubview (view.TextField);
// Configure
view.TextField.BackgroundColor = NSColor.Clear;
view.TextField.Bordered = false;
view.TextField.Selectable = false;
view.TextField.Editable = true;
// Wireup events
view.TextField.EditingEnded += (sender, e) => {
// Take action based on type
switch (view.Identifier) {
case "Product":
DataSource.Products [(int)view.TextField.Tag].Title = view.TextField.StringValue;
break;
case "Details":
DataSource.Products [(int)view.TextField.Tag].Description = view.TextField.StringValue;
break;
}
};
// Tag view
view.TextField.Tag = row;
}
Isso pega todas as configurações do Modo de Exibição de Texto que estavam sendo feitas anteriormente no GetViewForItem
método e as coloca em um único local chamável (já que a última coluna da tabela não inclui um Modo de Exibição de Texto, mas um Botão).
Finalmente, edite o GetViewForItem
método e torne-o parecido com o seguinte:
public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
// This pattern allows you reuse existing views when they are no-longer in use.
// If the returned view is null, you instance up a new view
// If a non-null view is returned, you modify it enough to reflect the new data
NSTableCellView view = (NSTableCellView)tableView.MakeView (tableColumn.Title, this);
if (view == null) {
view = new NSTableCellView ();
// Configure the view
view.Identifier = tableColumn.Title;
// Take action based on title
switch (tableColumn.Title) {
case "Product":
view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
view.AddSubview (view.ImageView);
view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
ConfigureTextField (view, row);
break;
case "Details":
view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
ConfigureTextField (view, row);
break;
case "Action":
// Create new button
var button = new NSButton (new CGRect (0, 0, 81, 16));
button.SetButtonType (NSButtonType.MomentaryPushIn);
button.Title = "Delete";
button.Tag = row;
// Wireup events
button.Activated += (sender, e) => {
// Get button and product
var btn = sender as NSButton;
var product = DataSource.Products [(int)btn.Tag];
// Configure alert
var alert = new NSAlert () {
AlertStyle = NSAlertStyle.Informational,
InformativeText = $"Are you sure you want to delete {product.Title}? This operation cannot be undone.",
MessageText = $"Delete {product.Title}?",
};
alert.AddButton ("Cancel");
alert.AddButton ("Delete");
alert.BeginSheetForResponse (Controller.View.Window, (result) => {
// Should we delete the requested row?
if (result == 1001) {
// Remove the given row from the dataset
DataSource.Products.RemoveAt((int)btn.Tag);
Controller.ReloadTable ();
}
});
};
// Add to view
view.AddSubview (button);
break;
}
}
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
view.ImageView.Image = NSImage.ImageNamed ("tag.png");
view.TextField.StringValue = DataSource.Products [(int)row].Title;
view.TextField.Tag = row;
break;
case "Details":
view.TextField.StringValue = DataSource.Products [(int)row].Description;
view.TextField.Tag = row;
break;
case "Action":
foreach (NSView subview in view.Subviews) {
var btn = subview as NSButton;
if (btn != null) {
btn.Tag = row;
}
}
break;
}
return view;
}
Vamos examinar várias seções deste código com mais detalhes. Primeiro, se um novo NSTableViewCell
estiver sendo criado, a ação será executada com base no nome da Coluna. Para as duas primeiras colunas (Produto e Detalhes), o novo ConfigureTextField
método é chamado.
Para a coluna Ação , um novo NSButton
é criado e adicionado à Célula como um Modo de Exibição Inferior:
// Create new button
var button = new NSButton (new CGRect (0, 0, 81, 16));
button.SetButtonType (NSButtonType.MomentaryPushIn);
button.Title = "Delete";
button.Tag = row;
...
// Add to view
view.AddSubview (button);
A propriedade Button Tag
é usada para manter o número da Linha que está sendo processada no momento. Esse número será usado posteriormente quando o usuário solicitar que uma linha seja excluída no evento do Activated
botão:
// Wireup events
button.Activated += (sender, e) => {
// Get button and product
var btn = sender as NSButton;
var product = DataSource.Products [(int)btn.Tag];
// Configure alert
var alert = new NSAlert () {
AlertStyle = NSAlertStyle.Informational,
InformativeText = $"Are you sure you want to delete {product.Title}? This operation cannot be undone.",
MessageText = $"Delete {product.Title}?",
};
alert.AddButton ("Cancel");
alert.AddButton ("Delete");
alert.BeginSheetForResponse (Controller.View.Window, (result) => {
// Should we delete the requested row?
if (result == 1001) {
// Remove the given row from the dataset
DataSource.Products.RemoveAt((int)btn.Tag);
Controller.ReloadTable ();
}
});
};
No início do manipulador de eventos, obtemos o botão e o produto que está na linha da tabela fornecida. Em seguida, um Alerta é apresentado ao usuário confirmando a exclusão da linha. Se o usuário optar por excluir a linha, a linha fornecida será removida da Fonte de Dados e a tabela será recarregada:
// Remove the given row from the dataset
DataSource.Products.RemoveAt((int)btn.Tag);
Controller.ReloadTable ();
Finalmente, se a Célula de Exibição de Tabela estiver sendo reutilizada em vez de ser criada nova, o código a seguir a configurará com base na Coluna que está sendo processada:
// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
view.ImageView.Image = NSImage.ImageNamed ("tag.png");
view.TextField.StringValue = DataSource.Products [(int)row].Title;
view.TextField.Tag = row;
break;
case "Details":
view.TextField.StringValue = DataSource.Products [(int)row].Description;
view.TextField.Tag = row;
break;
case "Action":
foreach (NSView subview in view.Subviews) {
var btn = subview as NSButton;
if (btn != null) {
btn.Tag = row;
}
}
break;
}
Para a coluna Ação , todas as Subexibições são verificadas até que a NSButton
seja encontrada e, em seguida, sua Tag
propriedade é atualizada para apontar para a Linha atual.
Com essas alterações em vigor, quando o aplicativo for executado, cada linha terá um botão Excluir :
Quando o usuário clicar em um botão Excluir , um alerta será exibido solicitando que ele exclua a Linha fornecida:
Se o usuário optar por excluir, a linha será removida e a tabela será redesenhada:
Exibições de tabela de vinculação de dados
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.
KVC (Key-Value Coding - Codificação de Chave-Valor) é 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 acesso (get/set
). Ao implementar acessadores compatíveis com Key-Value Coding em seu aplicativo Xamarin.Mac, você obtém acesso a outros recursos do macOS, como KVO (Key-Value Observando), Vinculação de Dados, Dados Principais, Ligações de Cacau e scriptabilidade.
Para obter mais informações, consulte a seção Vinculação de dados de exibição de tabela de nossa documentação de vinculação de dados e codificação de chave-valor.
Resumo
Este artigo deu uma olhada detalhada no trabalho com exibições de tabela em um aplicativo Xamarin.Mac. Vimos os diferentes tipos e usos de Exibições de Tabela, como criar e manter Exibições de Tabela no Construtor de Interfaces do Xcode e como trabalhar com Exibições de Tabela em código C#.