Исходные списки в Xamarin.Mac
В этой статье рассматривается работа с исходными списками в приложении Xamarin.Mac. В нем описывается создание и обслуживание исходных списков в Xcode и Конструкторе интерфейсов и взаимодействие с ними в коде C#.
При работе с C# и .NET в приложении Xamarin.Mac у вас есть доступ к тем же спискам источников, в которых работает Objective-C разработчик, и Xcode . Так как Xamarin.Mac интегрируется непосредственно с Xcode, с помощью конструктора интерфейсов Xcode можно создавать и поддерживать исходные списки (или при необходимости создавать их непосредственно в коде C#).
Исходный список — это особый тип представления структуры, используемый для отображения источника действия, например боковой панели в Finder или iTunes.
В этой статье мы рассмотрим основы работы с исходными списками в приложении Xamarin.Mac. Настоятельно рекомендуется сначала ознакомиться со статьей Hello, Mac , в частности в разделах "Введение в Xcode" и "Конструктор интерфейсов" и "Торговых точек" и "Действия ", поскольку рассматриваются основные понятия и методы, которые мы будем использовать в этой статье.
Вы можете ознакомиться с классами И методами C# в Objective-Cразделе документа Xamarin.Mac Internals, а также объяснить Register
Export
команды, используемые для подключения классов C# к Objective-C объектам и элементам пользовательского интерфейса.
Общие сведения о исходных списках
Как упоминалось выше, исходный список — это особый тип представления структуры, используемый для отображения источника действия, например боковой панели в Finder или iTunes. Исходный список — это тип таблицы, которая позволяет пользователю развертывать или свернуть строки иерархических данных. В отличие от представления таблицы элементы в исходном списке не находятся в неструктурированном списке, они организованы в иерархии, например в файлах и папках на жестком диске. Если элемент в списке источников содержит другие элементы, его можно развернуть или свернуть пользователем.
Исходный список — это специально стильное представление структуры (NSOutlineView
), которое само по себе является подклассом представления таблицы (NSTableView
) и таким образом наследует большую часть его поведения от родительского класса. В результате многие операции, поддерживаемые представлением структуры, также поддерживаются исходным списком. Приложение Xamarin.Mac имеет контроль над этими функциями и может настроить параметры исходного списка (в коде или построителе интерфейсов), чтобы разрешить или запретить определенные операции.
Исходный список не хранит собственные данные, вместо этого он полагается на источник данных (NSOutlineViewDataSource
) для предоставления строк и столбцов, необходимых по мере необходимости.
Поведение списка источников можно настроить, предоставив подкласс делегата представления структуры (NSOutlineViewDelegate
) для поддержки типа структуры, выбора функций, выбора элементов и редактирования, пользовательского отслеживания и пользовательских представлений для отдельных элементов.
Так как исходный список использует большую часть его поведения и функциональности с представлением таблицы и представлением структуры, вам может потребоваться перейти к нашей документации по представлениям таблиц и представлениям структуры , прежде чем продолжить работу с этой статьей.
Работа с исходными списками
Исходный список — это особый тип представления структуры, используемый для отображения источника действия, например боковой панели в Finder или iTunes. В отличие от представлений структуры, прежде чем определить исходный список в построителе интерфейсов, давайте создадим резервные классы в Xamarin.Mac.
Сначала создадим новый SourceListItem
класс для хранения данных для нашего исходного списка. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите SourceListItem
имя и нажмите кнопку "Создать":
Сделайте SourceListItem.cs
файл следующим образом:
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
}
}
В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите SourceListDataSource
имя и нажмите кнопку "Создать". Сделайте SourceListDataSource.cs
файл следующим образом:
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
}
}
Это предоставит данные для нашего исходного списка.
В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите SourceListDelegate
имя и нажмите кнопку "Создать". Сделайте SourceListDelegate.cs
файл следующим образом:
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
}
}
Это обеспечит поведение исходного списка.
Наконец, в Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл". Выберите общий>пустой класс, введите SourceListView
имя и нажмите кнопку "Создать". Сделайте SourceListView.cs
файл следующим образом:
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
}
}
При этом создается настраиваемый подкласс NSOutlineView
, который можно использовать для повторного использования (SourceListView
), который можно использовать для диска исходного списка в любом приложении Xamarin.Mac, которое мы делаем.
Создание и обслуживание исходных списков в Xcode
Теперь давайте создадим исходный список в построителе интерфейсов. Дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в построителе интерфейсов и перетащите представление из инспектора библиотеки, добавьте его в контроллер представления и установите его для изменения размера с помощью представления в редакторе ограничений:
Затем перетащите исходный список из инспектора библиотеки, добавьте его в левую сторону разделенного представления и установите его для изменения размера с помощью представления в редакторе ограничений:
Затем перейдите в представление удостоверений, выберите исходный список и измените его на:SourceListView
Наконец, создайте выход для нашего исходного списка, вызываемого SourceList
ViewController.h
в файле:
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Заполнение исходного списка
Давайте отредактируем RotationWindow.cs
файл в Visual Studio для Mac и сделайте его AwakeFromNib
следующим образом:
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);
}
Перед Initialize ()
добавлением элементов в него необходимо вызвать метод для выхода из исходного списка. Для каждой группы элементов мы создадим родительский элемент, а затем добавим вложенные элементы в этот элемент группы. Затем каждая группа добавляется в коллекцию SourceList.AddItem (...)
исходного списка. Последние две строки загружают данные для исходного списка и расширяют все группы:
// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);
Наконец, измените AppDelegate.cs
файл и сделайте DidFinishLaunching
метод следующим образом:
public override void DidFinishLaunching (NSNotification notification)
{
mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);
var rotation = new RotationWindowController ();
rotation.Window.MakeKeyAndOrderFront (this);
}
Если мы запускаем наше приложение, отобразится следующее:
Итоги
В этой статье подробно рассматривается работа с списками источников в приложении Xamarin.Mac. Мы узнали, как создавать и поддерживать исходные списки в построителе интерфейсов Xcode и как работать с исходными списками в коде C#.