Представления таблиц в Xamarin.Mac
В этой статье рассматривается работа с представлениями таблиц в приложении Xamarin.Mac. В нем описывается создание представлений таблиц в Xcode и Конструкторе интерфейсов и взаимодействие с ними в коде.
При работе с C# и .NET в приложении Xamarin.Mac у вас есть доступ к тем же представлениям таблиц, в которых работает Objective-C разработчик и Xcode . Так как Xamarin.Mac интегрируется непосредственно с Xcode, вы можете использовать построитель интерфейсов Xcode для создания и поддержания представлений таблиц (или при необходимости создавать их непосредственно в коде C#).
Представление таблицы отображает данные в табличном формате с одним или несколькими столбцами информации в нескольких строках. В зависимости от типа создаваемого представления таблицы пользователь может сортировать по столбцам, реорганизовать столбцы, добавлять столбцы, удалять столбцы или изменять данные, содержащиеся в таблице.
В этой статье мы рассмотрим основы работы с представлениями таблиц в приложении Xamarin.Mac. Настоятельно рекомендуется сначала ознакомиться со статьей Hello, Mac , в частности в разделах "Введение в Xcode" и "Конструктор интерфейсов" и "Торговых точек" и "Действия ", поскольку рассматриваются основные понятия и методы, которые мы будем использовать в этой статье.
Вы можете ознакомиться с классами И методами C# в Objective-Cразделе документа Xamarin.Mac Internals, а также объяснить Register
Export
команды, используемые для подключения классов C# к Objective-C объектам и элементам пользовательского интерфейса.
Общие сведения о представлениях таблиц
Представление таблицы отображает данные в табличном формате с одним или несколькими столбцами информации в нескольких строках. Представления таблиц отображаются внутри представлений прокрутки (NSScrollView
) и начинаются с macOS 10.7, а NSView
не ячейки (NSCell
) для отображения как строк, так и столбцов. Тем не менее, вы по-прежнему можете использовать NSCell
подкласс NSTableCellView
и создавать пользовательские строки и столбцы.
Представление таблицы не хранит собственные данные, а использует источник данных (NSTableViewDataSource
) для предоставления строк и столбцов, необходимых по мере необходимости.
Поведение представления таблицы можно настроить путем предоставления подкласса делегата представления таблицы (NSTableViewDelegate
) для поддержки управления столбцами таблицы, типа для выбора функций, выбора строк и редактирования, пользовательского отслеживания и пользовательских представлений для отдельных столбцов и строк.
При создании представлений таблиц Apple предлагает следующее:
- Разрешить пользователю сортировать таблицу, щелкнув заголовки столбцов.
- Создайте заголовки столбцов, которые являются существительными или короткими фразами существительных, описывающими данные, отображаемые в этом столбце.
Дополнительные сведения см. в разделе "Представления содержимого" в руководстве по пользовательскому интерфейсу Apple OS X.
Создание и обслуживание представлений таблиц в Xcode
При создании нового приложения Xamarin.Mac Cocoa вы получаете стандартное пустое окно по умолчанию. Эти окна определяются в файле, который автоматически включается в .storyboard
проект. Чтобы изменить дизайн окон, в Обозреватель решений дважды щелкните Main.storyboard
файл:
Откроется конструктор окон в построителе интерфейсов Xcode:
Введите table
в поле поиска инспектора библиотеки, чтобы упростить поиск элементов управления представлением таблицы:
Перетащите представление таблицы на контроллер представления в редакторе интерфейсов, заполните область содержимого контроллера представления и установите ее место, где оно сжимается и растет с окном в редакторе ограничений:
Выберите представление таблицы в иерархии интерфейса, а следующие свойства доступны в инспекторе атрибутов:
- Режим содержимого— позволяет использовать представления (
NSView
) или ячейки (NSCell
) для отображения данных в строках и столбцах. Начиная с macOS 10.7, следует использовать представления. - Строки группы с плавающей запятой — если
true
представление таблицы нарисует сгруппированные ячейки, как если бы они плавали. - Столбцы — определяет количество отображаемых столбцов.
- Заголовки — если
true
столбцы будут иметь заголовки. - Переупорядочение — если
true
пользователь сможет перетаскивать столбцы в таблице. - Изменение размера — если
true
пользователь сможет перетащить заголовки столбцов для изменения размера столбцов. - Размер столбцов — определяет, как таблица будет автоматически размерить столбцы.
- Выделение — управляет типом выделения таблицы, используемой при выборе ячейки.
- Альтернативные строки — если
true
, когда-либо другая строка будет иметь другой цвет фона. - Горизонтальная сетка — выбирает тип границы, рисуемой между ячейками по горизонтали.
- Вертикальная сетка — выбирает тип границы, рисуемой между ячейками по вертикали.
- Цвет сетки — задает цвет границы ячейки.
- Фон — задает цвет фона ячейки.
- Выбор . Позволяет управлять тем, как пользователь может выбирать ячейки в таблице следующим образом:
- Несколько — если
true
пользователь может выбрать несколько строк и столбцов. - Столбец — если
true
пользователь может выбрать столбцы. - Выбор типа — если
true
пользователь может ввести символ, чтобы выбрать строку. - Пустое — если
true
пользователю не требуется выбрать строку или столбец, таблица не позволяет выбирать ни в коем случае.
- Несколько — если
- Автосохранение — имя, в которое формат таблиц автоматически сохраняется.
- Сведения о столбцах — если
true
порядок и ширина столбцов будут автоматически сохранены. - Разрывы строк— выберите способ обработки разрывов строк ячейки.
- Усечение последней видимой строки . Если
true
ячейка будет усечена в данных не может помещаться внутри границ.
Внимание
Если вы не поддерживаете устаревшее приложение Xamarin.Mac, NSView
представления таблиц на основе таблицы должны использоваться в NSCell
представлениях таблиц на основе. NSCell
считается устаревшим и может не поддерживаться в будущем.
Выберите столбец таблицы в иерархии интерфейса, а следующие свойства доступны в инспекторе атрибутов:
- Заголовок — задает заголовок столбца.
- Выравнивание — установка выравнивания текста в ячейках.
- Заголовок шрифта — выбирает шрифт для текста заголовка ячейки.
- Ключ сортировки — это ключ , используемый для сортировки данных в столбце. Оставьте пустым, если пользователь не может сортировать этот столбец.
- Селектор — это действие , используемое для выполнения сортировки. Оставьте пустым, если пользователь не может сортировать этот столбец.
- Порядок — это порядок сортировки данных столбцов.
- Изменение размера — выбирает тип изменения размера столбца.
- Редактируемый — если
true
пользователь может изменять ячейки в таблице на основе ячеек. - Скрытый — если
true
столбец скрыт.
Вы также можете изменить размер столбца, перетащив его дескриптор (по вертикали на правой стороне столбца) влево или вправо.
Давайте выделите каждый столбец в представлении таблицы и присвойте первому столбцу заголовок Product
и второй Details
.
Выберите представление ячейки таблицы (NSTableViewCell
) в иерархии интерфейса и в инспекторе атрибутов доступны следующие свойства:
Это все свойства стандартного представления. Вы также можете изменить размер строк для этого столбца.
Выберите ячейку представления таблицы (по умолчанию это NSTextField
) в иерархии интерфейса, а следующие свойства доступны в инспекторе атрибутов:
У вас будут все свойства стандартного текстового поля, заданные здесь. По умолчанию стандартное текстовое поле используется для отображения данных ячейки в столбце.
Выберите представление ячейки таблицы (NSTableFieldCell
) в иерархии интерфейса и в инспекторе атрибутов доступны следующие свойства:
Ниже приведены наиболее важные параметры.
- Макет . Выберите, как выкладываются ячейки в этом столбце.
- Использует однострочный режим . Если
true
ячейка ограничена одной строкой. - Первая ширина макета среды выполнения — если
true
ячейка предпочитает набор ширины (вручную или автоматически) при первом запуске приложения. - Действие — управляет при отправке действия редактирования для ячейки.
- Поведение — определяет, можно ли выбрать или изменить ячейку.
- Форматированный текст — если
true
ячейка может отображать отформатированный и стильный текст. - Отмена — если
true
ячейка несет ответственность за его поведение отмены.
Выберите представление ячейки таблицы (NSTableFieldCell
) в нижней части столбца таблицы в иерархии интерфейса:
Это позволяет изменять представление ячеек таблицы, используемое в качестве базового шаблона для всех ячеек, созданных для данного столбца.
Добавление действий и точек
Как и любой другой элемент управления пользовательского интерфейса Cocoa, необходимо предоставить представление таблицы, и это столбцы и ячейки для кода C# с помощью действий и точек (на основе необходимых функций).
Процесс совпадает с любым элементом Table View, который мы хотим предоставить:
Перейдите в редактор помощника и убедитесь, что
ViewController.h
выбран файл:Выберите представление таблицы из иерархии интерфейса, щелкните элемент управления и перетащите его в
ViewController.h
файл.Создайте выход для представления таблицы:
ProductTable
Создайте точки для столбцов таблиц, которые также называются
ProductColumn
иDetailsColumn
:Сохраните изменения и вернитесь в Visual Studio для Mac для синхронизации с Xcode.
Затем мы напишем код, отображая некоторые данные для таблицы при запуске приложения.
Заполнение представления таблицы
С помощью представления таблицы, разработанного в построителе интерфейсов и предоставляемых через выход, необходимо создать код C#, чтобы заполнить его.
Сначала создадим новый Product
класс для хранения сведений для отдельных строк. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите Product
имя и нажмите кнопку "Создать":
Сделайте Product.cs
файл следующим образом:
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
}
}
Затем необходимо создать подкласс NSTableDataSource
для предоставления данных для таблицы по мере его запроса. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите ProductTableDataSource
имя и нажмите кнопку "Создать".
Измените ProductTableDataSource.cs
файл и сделайте его следующим образом:
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
}
}
Этот класс содержит хранилище для элементов представления таблиц и переопределяет GetRowCount
количество строк в таблице.
Наконец, необходимо создать подкласс NSTableDelegate
, чтобы обеспечить поведение для нашей таблицы. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый файл" ... Выберите общий>пустой класс, введите ProductTableDelegate
имя и нажмите кнопку "Создать".
Измените ProductTableDelegate.cs
файл и сделайте его следующим образом:
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
}
}
При создании экземпляра ProductTableDelegate
также передаются экземпляры ProductTableDataSource
, предоставляющие данные для таблицы. Метод GetViewForItem
отвечает за возврат представления (данных) для отображения ячейки для заданного столбца и строки. Если это возможно, существующее представление будет повторно использоваться для отображения ячейки, если она не должна быть создана.
Чтобы заполнить таблицу, давайте отредактируем ViewController.cs
файл и создадим AwakeFromNib
метод следующим образом:
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);
}
Если запустить приложение, отобразится следующее:
Сортировка по столбцу
Давайте разрешим пользователю отсортировать данные в таблице, щелкнув заголовок столбца. Сначала дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в Конструкторе интерфейсов. Product
Выберите столбец, введите Title
ключ compare:
сортировки для селектора и выберите Ascending
для заказа:
Details
Выберите столбец, введите Description
ключ compare:
сортировки для селектора и выберите Ascending
для заказа:
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Теперь давайте отредактируем ProductTableDataSource.cs
файл и добавьте следующие методы:
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 ();
}
Метод Sort
позволяет отсортировать данные в источнике данных на основе заданного Product
поля класса в порядке возрастания или убывания. Переопределенный SortDescriptorsChanged
метод будет вызываться каждый раз, когда используется нажатие заголовка столбца. Он будет передан значение ключа, заданное в конструкторе интерфейсов, и порядок сортировки для этого столбца.
Если запустить приложение и щелкнуть заголовки столбцов, строки будут отсортированы по такому столбцу:
Выбор строки
Если вы хотите разрешить пользователю выбрать одну строку, дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в Конструкторе интерфейсов. Выберите представление таблицы в иерархии интерфейса и снимите флажок "Несколько" в инспекторе атрибутов:
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Затем измените ProductTableDelegate.cs
файл и добавьте следующий метод:
public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
return true;
}
Это позволит пользователю выбрать любую одну строку в представлении таблицы. Вернитесь false
к ShouldSelectRow
любой строке, которую не хотите, чтобы пользователь мог выбрать или false
для каждой строки, если вы не хотите, чтобы пользователь мог выбрать какие-либо строки.
Представление таблицы (NSTableView
) содержит следующие методы для работы с выбором строк:
DeselectRow(nint)
— отменяет выбор заданной строки в таблице.SelectRow(nint,bool)
— выбирает указанную строку. Передайтеfalse
второй параметр, чтобы выбрать только одну строку за раз.SelectedRow
— возвращает текущую строку, выбранную в таблице.IsRowSelected(nint)
— возвращает значениеtrue
, если выбрана заданная строка.
Выбор нескольких строк
Если вы хотите разрешить пользователю выбрать несколько строк, дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в Конструкторе интерфейсов. Выберите представление таблицы в иерархии интерфейса и установите флажок "Несколько" в инспекторе атрибутов:
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Затем измените ProductTableDelegate.cs
файл и добавьте следующий метод:
public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
return true;
}
Это позволит пользователю выбрать любую одну строку в представлении таблицы. Вернитесь false
к ShouldSelectRow
любой строке, которую не хотите, чтобы пользователь мог выбрать или false
для каждой строки, если вы не хотите, чтобы пользователь мог выбрать какие-либо строки.
Представление таблицы (NSTableView
) содержит следующие методы для работы с выбором строк:
DeselectAll(NSObject)
— отменяет выбор всех строк в таблице. Используйтеthis
первый параметр для отправки в объекте, выполняющего выбор.DeselectRow(nint)
— отменяет выбор заданной строки в таблице.SelectAll(NSobject)
— выбирает все строки в таблице. Используйтеthis
первый параметр для отправки в объекте, выполняющего выбор.SelectRow(nint,bool)
— выбирает указанную строку. Передайте второй параметр снимите выделение и выберите только одну строку, передайтеfalse
true
, чтобы расширить выделение и включить эту строку.SelectRows(NSIndexSet,bool)
— выбирает заданный набор строк. Передайтеfalse
второй параметр снимите выделение и выберите только эти строки, передайтеtrue
, чтобы расширить выделение и включить эти строки.SelectedRow
— возвращает текущую строку, выбранную в таблице.SelectedRows
— возвращаетNSIndexSet
индексы выбранных строк.SelectedRowCount
— возвращает количество выбранных строк.IsRowSelected(nint)
— возвращает значениеtrue
, если выбрана заданная строка.
Тип для выбора строки
Если вы хотите разрешить пользователю вводить символ с выбранным представлением таблицы и выбрать первую строку с таким символом, дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в Конструкторе интерфейсов. Выберите представление таблицы в иерархии интерфейса и установите флажок "Выбрать тип" в инспекторе атрибутов:
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Теперь давайте отредактируем ProductTableDelegate.cs
файл и добавьте следующий метод:
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;
}
Метод GetNextTypeSelectMatch
принимает заданный searchString
и возвращает строку первой Product
строки, которая содержит строку в ней Title
.
Если запустить приложение и ввести символ, то будет выбрана строка:
Изменение порядка столбцов
Если вы хотите разрешить пользователю перетаскивать столбцы переупорядочения в представлении таблицы, дважды щелкните Main.storyboard
файл, чтобы открыть его для редактирования в Конструкторе интерфейсов. Выберите представление таблицы в иерархии интерфейса и установите флажок "Изменить порядок" в инспекторе атрибутов:
Если мы предоставим значение для свойства автосохранение и проверьте поле "Сведения о столбцах", все изменения, внесенные в макет таблицы, будут автоматически сохранены для нас и восстановлены при следующем запуске приложения.
Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.
Теперь давайте отредактируем ProductTableDelegate.cs
файл и добавьте следующий метод:
public override bool ShouldReorder (NSTableView tableView, nint columnIndex, nint newColumnIndex)
{
return true;
}
Метод ShouldReorder
должен возвращать true
любой столбец, который требуется разрешить переупорядочению в другой newColumnIndex
возвращаемый false
столбец;
Если мы запускаем приложение, мы можем перетащить заголовки столбцов вокруг, чтобы изменить порядок наших столбцов:
Редактирование ячеек
Если вы хотите разрешить пользователю изменять значения для данной ячейки, измените ProductTableDelegate.cs
файл и измените GetViewForItem
метод следующим образом:
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;
}
Теперь, если мы запустите приложение, пользователь может изменить ячейки в представлении таблицы:
Использование изображений в представлениях таблиц
Чтобы включить изображение в ячейку в NSTableView
ячейку, необходимо изменить способ возврата данных методом представления NSTableViewDelegate's
GetViewForItem
таблицы, чтобы использовать NSTableCellView
вместо типичных NSTextField
. Например:
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;
}
Дополнительные сведения см. в разделе "Использование изображений с представлениями таблиц" в документации по работе с изображением .
Добавление кнопки удаления в строку
В зависимости от требований приложения могут возникнуть случаи, когда необходимо указать кнопку действия для каждой строки в таблице. В качестве примера этого давайте разверните пример представления таблиц, созданный выше, чтобы включить кнопку "Удалить " в каждой строке.
Сначала измените построитель Main.storyboard
интерфейсов Xcode, выберите представление таблицы и увеличьте число столбцов до трех (3). Затем измените заголовок нового столбца Action
на :
Сохраните изменения в раскадровке и вернитесь к Visual Studio для Mac для синхронизации изменений.
Затем измените файл и добавьте следующий открытый ViewController.cs
метод:
public void ReloadTable ()
{
ProductTable.ReloadData ();
}
В том же файле измените создание нового делегата представления таблиц внутри ViewDidLoad
метода следующим образом:
// Populate the Product Table
ProductTable.DataSource = DataSource;
ProductTable.Delegate = new ProductTableDelegate (this, DataSource);
Теперь измените ProductTableDelegate.cs
файл, чтобы включить частное подключение к контроллеру представления и взять контроллер в качестве параметра при создании нового экземпляра делегата:
#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
Затем добавьте в класс следующий новый закрытый метод:
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;
}
Это принимает все конфигурации представления текста, которые ранее были выполнены в GetViewForItem
методе, и помещает их в одно вызываемое расположение (так как последний столбец таблицы не включает текстовое представление, а кнопку).
Наконец, измените GetViewForItem
метод и сделайте его следующим образом:
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;
}
Давайте рассмотрим несколько разделов этого кода более подробно. Во-первых, если создается новое NSTableViewCell
действие, выполняется на основе имени столбца. Для первых двух столбцов (Product и Details) вызывается новый ConfigureTextField
метод.
Для столбца "Действие " NSButton
создается и добавляется в ячейку в виде подчиненного представления:
// 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);
Свойство Button Tag
используется для хранения числа обрабатываемых строк. Это число будет использоваться позже, когда пользователь запрашивает удаление строки в событии Кнопки Activated
:
// 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 ();
}
});
};
В начале обработчика событий мы получаем кнопку и продукт, который находится в заданной строке таблицы. Затем пользователю будет представлено оповещение, подтверждающее удаление строки. Если пользователь решит удалить строку, данная строка удаляется из источника данных, а таблица перезагрузится:
// Remove the given row from the dataset
DataSource.Products.RemoveAt((int)btn.Tag);
Controller.ReloadTable ();
Наконец, если ячейка представления таблицы повторно используется вместо создания новой, следующий код настраивает его на основе обрабатываемого столбца:
// 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;
}
Для столбца Действия все вложенные представления сканируются до тех пор, пока не будет найден, NSButton
то его Tag
свойство обновляется до точки в текущей строке.
При наличии этих изменений при запуске приложения каждая строка будет иметь кнопку "Удалить ":
Когда пользователь нажимает кнопку "Удалить ", появится оповещение с просьбой удалить указанную строку:
Если пользователь выбирает удаление, строка будет удалена, а таблица будет перезабрана:
Представления таблицы привязки данных
Используя методы кодирования ключей и привязки данных в приложении Xamarin.Mac, вы можете значительно уменьшить объем кода, который необходимо написать и поддерживать для заполнения и работы с элементами пользовательского интерфейса. Кроме того, вы можете дополнительно отсогласовать резервные данные (модель данных) с интерфейсного пользовательского интерфейса (model-View-Controller), что упрощает обслуживание, более гибкое проектирование приложений.
Кодирование ключей (KVC) — это механизм косвенного доступа к свойствам объекта с помощью ключей (специально отформатированных строк) для идентификации свойств вместо доступа к ним через переменные экземпляра или методы доступа (get/set
). Реализуя соответствующие методы доступа к кодированию ключей в приложении Xamarin.Mac, вы получаете доступ к другим функциям macOS, таким как наблюдение за ключевым значением (KVO), привязка данных, основные данные, привязки Какао и скрипты.
Дополнительные сведения см. в разделе "Привязка данных представления данных" в документации по привязке данных и кодированию ключа.
Итоги
В этой статье подробно рассматривается работа с представлениями таблиц в приложении Xamarin.Mac. Мы видели различные типы и использование представлений таблиц, как создавать и поддерживать представления таблиц в построителе интерфейсов Xcode и как работать с представлениями таблиц в коде C#.