Listas de origem no Xamarin.Mac
Este artigo aborda o trabalho com listas de origem em um aplicativo Xamarin.Mac. Ele descreve a criação e a manutenção de listas de origem no Xcode e no Construtor de Interfaces e a interação com elas no código C#.
Ao trabalhar com C# e .NET em um aplicativo Xamarin.Mac, você tem acesso às mesmas Listas de Origem que um desenvolvedor que trabalha e Objective-C o Xcode tem. Como o Xamarin.Mac se integra diretamente ao Xcode, você pode usar o Construtor de Interfaces do Xcode para criar e manter suas Listas de Origem (ou, opcionalmente, criá-las diretamente no código C#).
Uma Lista de Origens é um tipo especial de Visualização de Estrutura de Tópicos usado para mostrar a origem de uma ação, como a barra lateral no Finder ou no iTunes.
Neste artigo, abordaremos as noções básicas de como trabalhar com Listas de Origem 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 Interfaces e Saídas e Ações , pois ele aborda os principais conceitos e técnicas que usaremos neste artigo.
Talvez você queira dar uma olhada na seção Expondo classes/métodos C# para Objective-Cdo documento Internos do Xamarin.Mac também, ele explica os Register
comandos e Export
usados para conectar suas classes C# a Objective-C objetos e elementos de interface do usuário.
Introdução às listas de fontes
Como dito acima, uma Lista de Origem é um tipo especial de Visualização de Estrutura de Tópicos usado para mostrar a origem de uma ação, como a barra lateral no Finder ou iTunes. Uma Lista de Origem é um tipo de Tabela que permite ao usuário expandir ou recolher linhas de dados hierárquicos. Ao contrário de uma Exibição de Tabela, os itens em uma Lista de Origem não estão em uma lista simples, eles são organizados em uma hierarquia, como arquivos e pastas em um disco rígido. Se um item em uma Lista de Origem contiver outros itens, ele poderá ser expandido ou recolhido pelo usuário.
A Lista de Fontes é uma Visualização de Estrutura de Tópicos (NSOutlineView
), que por sua vez é uma subclasse da Visualização de Tabela (NSTableView
) e, como tal, herda muito de seu comportamento de sua classe pai. Como resultado, muitas operações suportadas por uma Exibição de Estrutura de Tópicos também são suportadas por uma Lista de Origem. Um aplicativo Xamarin.Mac tem controle desses recursos e pode configurar os parâmetros da Lista de Origem (no código ou no Construtor de Interfaces) para permitir ou não permitir determinadas operações.
Uma Lista de Fontes não armazena seus próprios dados, em vez disso, depende de uma Fonte de Dados (NSOutlineViewDataSource
) para fornecer as linhas e colunas necessárias, conforme necessário.
O comportamento de uma Lista de Origem pode ser personalizado fornecendo uma subclasse do Delegado de Exibição de Estrutura de Tópicos (NSOutlineViewDelegate
) para dar suporte ao tipo de Estrutura de Tópicos para selecionar funcionalidade, seleção e edição de itens, rastreamento personalizado e exibições personalizadas para itens individuais.
Como uma Lista de Origem compartilha muito de seu comportamento e funcionalidade com um Modo de Exibição de Tabela e um Modo de Exibição de Estrutura de Tópicos, talvez você queira examinar nossa documentação de Modos de Exibição de Tabela e Modos de Exibição de Estrutura de Tópicos antes de continuar com este artigo.
Trabalhando com listas de origem
Uma Lista de Origens é um tipo especial de Visualização de Estrutura de Tópicos usado para mostrar a origem de uma ação, como a barra lateral no Finder ou no iTunes. Ao contrário dos Modos de Exibição de Estrutura de Tópicos, antes de definirmos nossa Lista de Origem no Construtor de Interfaces, vamos criar as classes de suporte no Xamarin.Mac.
Primeiro, vamos criar uma nova SourceListItem
classe para armazenar os dados de nossa Lista de Origem. No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione Geral>Classe Vazia, digite SourceListItem
para o Nome e clique no botão Novo:
Faça com que o SourceListItem.cs
arquivo tenha a seguinte aparência:
using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListItem: NSObject, IEnumerator, IEnumerable
{
#region Private Properties
private string _title;
private NSImage _icon;
private string _tag;
private List<SourceListItem> _items = new List<SourceListItem> ();
#endregion
#region Computed Properties
public string Title {
get { return _title; }
set { _title = value; }
}
public NSImage Icon {
get { return _icon; }
set { _icon = value; }
}
public string Tag {
get { return _tag; }
set { _tag=value; }
}
#endregion
#region Indexer
public SourceListItem this[int index]
{
get
{
return _items[index];
}
set
{
_items[index] = value;
}
}
public int Count {
get { return _items.Count; }
}
public bool HasChildren {
get { return (Count > 0); }
}
#endregion
#region Enumerable Routines
private int _position = -1;
public IEnumerator GetEnumerator()
{
_position = -1;
return (IEnumerator)this;
}
public bool MoveNext()
{
_position++;
return (_position < _items.Count);
}
public void Reset()
{_position = -1;}
public object Current
{
get
{
try
{
return _items[_position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
#endregion
#region Constructors
public SourceListItem ()
{
}
public SourceListItem (string title)
{
// Initialize
this._title = title;
}
public SourceListItem (string title, string icon)
{
// Initialize
this._title = title;
this._icon = NSImage.ImageNamed (icon);
}
public SourceListItem (string title, string icon, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = NSImage.ImageNamed (icon);
this.Clicked = clicked;
}
public SourceListItem (string title, NSImage icon)
{
// Initialize
this._title = title;
this._icon = icon;
}
public SourceListItem (string title, NSImage icon, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = icon;
this.Clicked = clicked;
}
public SourceListItem (string title, NSImage icon, string tag)
{
// Initialize
this._title = title;
this._icon = icon;
this._tag = tag;
}
public SourceListItem (string title, NSImage icon, string tag, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = icon;
this._tag = tag;
this.Clicked = clicked;
}
#endregion
#region Public Methods
public void AddItem(SourceListItem item) {
_items.Add (item);
}
public void AddItem(string title) {
_items.Add (new SourceListItem (title));
}
public void AddItem(string title, string icon) {
_items.Add (new SourceListItem (title, icon));
}
public void AddItem(string title, string icon, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, clicked));
}
public void AddItem(string title, NSImage icon) {
_items.Add (new SourceListItem (title, icon));
}
public void AddItem(string title, NSImage icon, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, clicked));
}
public void AddItem(string title, NSImage icon, string tag) {
_items.Add (new SourceListItem (title, icon, tag));
}
public void AddItem(string title, NSImage icon, string tag, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, tag, clicked));
}
public void Insert(int n, SourceListItem item) {
_items.Insert (n, item);
}
public void RemoveItem(SourceListItem item) {
_items.Remove (item);
}
public void RemoveItem(int n) {
_items.RemoveAt (n);
}
public void Clear() {
_items.Clear ();
}
#endregion
#region Events
public delegate void ClickedDelegate();
public event ClickedDelegate Clicked;
internal void RaiseClickedEvent() {
// Inform caller
if (this.Clicked != null)
this.Clicked ();
}
#endregion
}
}
No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione Geral>Classe Vazia, digite SourceListDataSource
para o Nome e clique no botão Novo. Faça com que o SourceListDataSource.cs
arquivo tenha a seguinte aparência:
using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListDataSource : NSOutlineViewDataSource
{
#region Private Variables
private SourceListView _controller;
#endregion
#region Public Variables
public List<SourceListItem> Items = new List<SourceListItem>();
#endregion
#region Constructors
public SourceListDataSource (SourceListView controller)
{
// Initialize
this._controller = controller;
}
#endregion
#region Override Properties
public override nint GetChildrenCount (NSOutlineView outlineView, Foundation.NSObject item)
{
if (item == null) {
return Items.Count;
} else {
return ((SourceListItem)item).Count;
}
}
public override bool ItemExpandable (NSOutlineView outlineView, Foundation.NSObject item)
{
return ((SourceListItem)item).HasChildren;
}
public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, Foundation.NSObject item)
{
if (item == null) {
return Items [(int)childIndex];
} else {
return ((SourceListItem)item) [(int)childIndex];
}
}
public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
{
return new NSString (((SourceListItem)item).Title);
}
#endregion
#region Internal Methods
internal SourceListItem ItemForRow(int row) {
int index = 0;
// Look at each group
foreach (SourceListItem item in Items) {
// Is the row inside this group?
if (row >= index && row <= (index + item.Count)) {
return item [row - index - 1];
}
// Move index
index += item.Count + 1;
}
// Not found
return null;
}
#endregion
}
}
Isso fornecerá os dados para nossa Lista de Fontes.
No Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione Geral>Classe Vazia, digite SourceListDelegate
para o Nome e clique no botão Novo. Faça com que o SourceListDelegate.cs
arquivo tenha a seguinte aparência:
using System;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListDelegate : NSOutlineViewDelegate
{
#region Private variables
private SourceListView _controller;
#endregion
#region Constructors
public SourceListDelegate (SourceListView controller)
{
// Initialize
this._controller = controller;
}
#endregion
#region Override Methods
public override bool ShouldEditTableColumn (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
{
return false;
}
public override NSCell GetCell (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
{
nint row = outlineView.RowForItem (item);
return tableColumn.DataCellForRow (row);
}
public override bool IsGroupItem (NSOutlineView outlineView, Foundation.NSObject item)
{
return ((SourceListItem)item).HasChildren;
}
public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
{
NSTableCellView view = null;
// Is this a group item?
if (((SourceListItem)item).HasChildren) {
view = (NSTableCellView)outlineView.MakeView ("HeaderCell", this);
} else {
view = (NSTableCellView)outlineView.MakeView ("DataCell", this);
view.ImageView.Image = ((SourceListItem)item).Icon;
}
// Initialize view
view.TextField.StringValue = ((SourceListItem)item).Title;
// Return new view
return view;
}
public override bool ShouldSelectItem (NSOutlineView outlineView, Foundation.NSObject item)
{
return (outlineView.GetParent (item) != null);
}
public override void SelectionDidChange (NSNotification notification)
{
NSIndexSet selectedIndexes = _controller.SelectedRows;
// More than one item selected?
if (selectedIndexes.Count > 1) {
// Not handling this case
} else {
// Grab the item
var item = _controller.Data.ItemForRow ((int)selectedIndexes.FirstIndex);
// Was an item found?
if (item != null) {
// Fire the clicked event for the item
item.RaiseClickedEvent ();
// Inform caller of selection
_controller.RaiseItemSelected (item);
}
}
}
#endregion
}
}
Isso fornecerá o comportamento de nossa Lista de Fontes.
Por fim, no Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo... Selecione Geral>Classe Vazia, digite SourceListView
para o Nome e clique no botão Novo. Faça com que o SourceListView.cs
arquivo tenha a seguinte aparência:
using System;
using AppKit;
using Foundation;
namespace MacOutlines
{
[Register("SourceListView")]
public class SourceListView : NSOutlineView
{
#region Computed Properties
public SourceListDataSource Data {
get {return (SourceListDataSource)this.DataSource; }
}
#endregion
#region Constructors
public SourceListView ()
{
}
public SourceListView (IntPtr handle) : base(handle)
{
}
public SourceListView (NSCoder coder) : base(coder)
{
}
public SourceListView (NSObjectFlag t) : base(t)
{
}
#endregion
#region Override Methods
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
}
#endregion
#region Public Methods
public void Initialize() {
// Initialize this instance
this.DataSource = new SourceListDataSource (this);
this.Delegate = new SourceListDelegate (this);
}
public void AddItem(SourceListItem item) {
if (Data != null) {
Data.Items.Add (item);
}
}
#endregion
#region Events
public delegate void ItemSelectedDelegate(SourceListItem item);
public event ItemSelectedDelegate ItemSelected;
internal void RaiseItemSelected(SourceListItem item) {
// Inform caller
if (this.ItemSelected != null) {
this.ItemSelected (item);
}
}
#endregion
}
}
Isso cria uma subclasse personalizada e reutilizável de (SourceListView
) que podemos usar para conduzir a Lista de NSOutlineView
Origem em qualquer aplicativo Xamarin.Mac que criarmos.
Criando e mantendo listas de origem no Xcode
Agora, vamos projetar nossa Lista de Origem no Construtor de Interfaces. Clique duas vezes no Main.storyboard
arquivo para abri-lo para edição no Construtor de Interfaces e arraste uma Exibição dividida do Inspetor de biblioteca, adicione-a ao Controlador de exibição e configure-a para redimensionar com a exibição no Editor de restrições:
Em seguida, arraste uma Lista de Código-Fonte do Inspetor de Biblioteca, adicione-a ao lado esquerdo da Exibição dividida e configure-a para redimensionar com a Exibição no Editor de restrições:
Em seguida, alterne para o Modo de Exibição de Identidade, selecione a Lista de Origem e altere sua Classe para SourceListView
:
Por fim, crie uma saída para nossa lista de fontes chamada SourceList
no ViewController.h
arquivo:
Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.
Preenchendo a lista de origem
Vamos editar o RotationWindow.cs
arquivo no Visual Studio para Mac e fazer com que seu AwakeFromNib
método seja semelhante ao seguinte:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Populate source list
SourceList.Initialize ();
var library = new SourceListItem ("Library");
library.AddItem ("Venues", "house.png", () => {
Console.WriteLine("Venue Selected");
});
library.AddItem ("Singers", "group.png");
library.AddItem ("Genre", "cards.png");
library.AddItem ("Publishers", "box.png");
library.AddItem ("Artist", "person.png");
library.AddItem ("Music", "album.png");
SourceList.AddItem (library);
// Add Rotation
var rotation = new SourceListItem ("Rotation");
rotation.AddItem ("View Rotation", "redo.png");
SourceList.AddItem (rotation);
// Add Kiosks
var kiosks = new SourceListItem ("Kiosks");
kiosks.AddItem ("Sign-in Station 1", "imac");
kiosks.AddItem ("Sign-in Station 2", "ipad");
SourceList.AddItem (kiosks);
// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);
}
O Initialize ()
método precisa ser chamado em relação ao Outlet da nossa Lista de Origem antes que qualquer item seja adicionado a ele. Para cada grupo de itens, criamos um item pai e, em seguida, adicionamos os subitens a esse item de grupo. Cada grupo é então adicionado à coleção SourceList.AddItem (...)
da Lista de Origem. As duas últimas linhas carregam os dados para a Lista de Origem e expandem todos os grupos:
// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);
Por fim, edite o AppDelegate.cs
arquivo e faça com que o DidFinishLaunching
método fique parecido com o seguinte:
public override void DidFinishLaunching (NSNotification notification)
{
mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);
var rotation = new RotationWindowController ();
rotation.Window.MakeKeyAndOrderFront (this);
}
Se executarmos nosso aplicativo, o seguinte será exibido:
Resumo
Este artigo examinou detalhadamente como trabalhar com Listas de Origem em um aplicativo Xamarin.Mac. Vimos como criar e manter Listas de Origem no Construtor de Interfaces do Xcode e como trabalhar com Listas de Origem no código C#.