Vistas de colección en Xamarin.Mac

En este artículo se describe cómo trabajar con vistas de colección en una aplicación de Xamarin.Mac. Se trata la creación y el mantenimiento de vistas de colección en Xcode Interface Builder y cómo trabajar con ellas mediante programación.

Cuando se trabaja con C# y .NET en una aplicación de Xamarin.Mac, el desarrollador tiene acceso a los mismos controles de vista de colección de AppKit que un desarrollador que trabaja en Objective-CObjective-C Dado que Xamarin.Mac se integra directamente con Xcode, el desarrollador usa las Interface Builder de Xcode para crear y mantener vistas de colección.

muestra NSCollectionView una cuadrícula de subvistas organizadas mediante NSCollectionViewLayout . Cada subvista de la cuadrícula se representa mediante un que administra la carga del contenido de la vista NSCollectionViewItem desde un .xib archivo.

Ejecución de una aplicación de ejemplo

En este artículo se tratan los conceptos básicos de trabajar con vistas de colección en una aplicación de Xamarin.Mac. Se recomienda encarecidamente que trabaje primero en el artículo Hello, Mac, en concreto en las secciones Introduction to Xcode and Interface Builder and Outlets and Actions (Introducción a Xcode y Interface Builder y salidas y acciones), ya que trata los conceptos y técnicas clave que se usan en este artículo.

También puede echar un vistazo a la sección del documento Exposing C# classes / methods to Objective-CExposing C# classes / methods to Objective-C internos de Xamarin.Mac), donde se explican los comandos y que se usan para conectar las clases de C# a objetos y elementos de interfaz de RegisterExportObjective-C usuario.

Acerca de las vistas de colección

El objetivo principal de una vista de colección ( ) es organizar visualmente un grupo de objetos de forma organizada mediante un diseño de vista de colección ( ), con cada objeto individual ( ) obteniendo su propia vista en la colección más NSCollectionViewNSCollectionViewLayoutNSCollectionViewItem grande. Las vistas de colección funcionan mediante técnicas de enlace de datos Key-Value codificación y, por tanto, debe leer la documentación sobre enlace de datos y codificación Key-Value antes de continuar con este artículo.

La vista de colección no tiene ningún elemento de vista de colección integrado estándar (como lo hace una vista de esquema o tabla), por lo que el desarrollador es responsable de diseñar e implementar una vista de prototipo con otros controles de AppKit, como campos de imagen, campos de texto, etiquetas, etc. Esta vista prototipo se usará para mostrar y trabajar con cada elemento que administra la vista de colección y se almacena en un archivo.

Dado que el desarrollador es responsable de la apariencia de un elemento de vista de colección, la vista de colección no tiene compatibilidad integrada para resaltar un elemento seleccionado en la cuadrícula. La implementación de esta característica se trata en este artículo.

Definir el modelo de datos

Antes de enlazar datos a una vista de colección en Interface Builder, se debe definir una clase compatible con la codificación de Key-Value (KVC)/Key-Value Observing (KVO) en la aplicación Xamarin.Mac para que actúe como modelo de datos para el enlace. El modelo de datos proporciona todos los datos que se mostrarán en la colección y recibe cualquier modificación en los datos que el usuario realiza en la interfaz de usuario mientras ejecuta la aplicación.

Tomemos el ejemplo de una aplicación que administra un grupo de empleados; se podría usar la clase siguiente para definir el modelo de datos:

using System;
using Foundation;
using AppKit;

namespace MacDatabinding
{
    [Register("PersonModel")]
    public class PersonModel : NSObject
    {
        #region Private Variables
        private string _name = "";
        private string _occupation = "";
        private bool _isManager = false;
        private NSMutableArray _people = new NSMutableArray();
        #endregion

        #region Computed Properties
        [Export("Name")]
        public string Name {
            get { return _name; }
            set {
                WillChangeValue ("Name");
                _name = value;
                DidChangeValue ("Name");
            }
        }

        [Export("Occupation")]
        public string Occupation {
            get { return _occupation; }
            set {
                WillChangeValue ("Occupation");
                _occupation = value;
                DidChangeValue ("Occupation");
            }
        }

        [Export("isManager")]
        public bool isManager {
            get { return _isManager; }
            set {
                WillChangeValue ("isManager");
                WillChangeValue ("Icon");
                _isManager = value;
                DidChangeValue ("isManager");
                DidChangeValue ("Icon");
            }
        }

        [Export("isEmployee")]
        public bool isEmployee {
            get { return (NumberOfEmployees == 0); }
        }

        [Export("Icon")]
        public NSImage Icon
        {
            get
            {
                if (isManager)
                {
                    return NSImage.ImageNamed("IconGroup");
                }
                else
                {
                    return NSImage.ImageNamed("IconUser");
                }
            }
        }

        [Export("personModelArray")]
        public NSArray People {
            get { return _people; }
        }

        [Export("NumberOfEmployees")]
        public nint NumberOfEmployees {
            get { return (nint)_people.Count; }
        }
        #endregion

        #region Constructors
        public PersonModel ()
        {
        }

        public PersonModel (string name, string occupation)
        {
            // Initialize
            this.Name = name;
            this.Occupation = occupation;
        }

        public PersonModel (string name, string occupation, bool manager)
        {
            // Initialize
            this.Name = name;
            this.Occupation = occupation;
            this.isManager = manager;
        }
        #endregion

        #region Array Controller Methods
        [Export("addObject:")]
        public void AddPerson(PersonModel person) {
            WillChangeValue ("personModelArray");
            isManager = true;
            _people.Add (person);
            DidChangeValue ("personModelArray");
        }

        [Export("insertObject:inPersonModelArrayAtIndex:")]
        public void InsertPerson(PersonModel person, nint index) {
            WillChangeValue ("personModelArray");
            _people.Insert (person, index);
            DidChangeValue ("personModelArray");
        }

        [Export("removeObjectFromPersonModelArrayAtIndex:")]
        public void RemovePerson(nint index) {
            WillChangeValue ("personModelArray");
            _people.RemoveObject (index);
            DidChangeValue ("personModelArray");
        }

        [Export("setPersonModelArray:")]
        public void SetPeople(NSMutableArray array) {
            WillChangeValue ("personModelArray");
            _people = array;
            DidChangeValue ("personModelArray");
        }
        #endregion
    }
}

El PersonModel modelo de datos se usará en el resto de este artículo.

Trabajar con una vista de colección

El enlace de datos con una vista de colección es muy parecido al enlace con una vista de tabla, como se usa para proporcionar NSCollectionViewDataSource datos para la colección. Puesto que la vista de colección no tiene un formato de presentación preestablecido, se requiere más trabajo para proporcionar comentarios sobre la interacción del usuario y realizar un seguimiento de la selección del usuario.

Creación del prototipo de celda

Puesto que la vista de recopilación no incluye un prototipo de celda predeterminado, el desarrollador deberá agregar uno o varios archivos a la aplicación Xamarin.Mac para definir el diseño y el contenido de las .xib celdas individuales.

Haga lo siguiente:

  1. En la Explorador de soluciones, haga clic con el botón derecho en el nombre del proyecto y seleccione Agregarnuevo archivo...

  2. Seleccione Controlador devista mac,asíéquele un nombre (como en este ejemplo) y haga clic en el botón Nuevo para crear:

    Adición de un nuevo controlador de vistas

    Esto agregará un EmployeeItem.cs archivo y a la solución del EmployeeItemController.csEmployeeItemController.xib proyecto.

  3. Haga doble clic en EmployeeItemController.xib el archivo para abrirlo para editarlo en la página de Xcode Interface Builder.

  4. Agregue NSBox un control , NSImageView y dos controles a la vista y NSLabel desagréguelos de la siguiente manera:

    Diseño del diseño del prototipo de celda

  5. Abra el Editor del asistente y cree una salida para para que se pueda usar para indicar el estado de selección de una celda:

    Exponer el NSBox en una salida

  6. Vuelva al Editor estándar y seleccione la Vista de imágenes.

  7. En el Inspector de enlace,seleccione Enlazar alpropietario del archivo y escriba una ruta de acceso de clave de modelo de :

    Enlazar el icono

  8. Seleccione la primera etiqueta y, en el Inspectorde enlace, seleccione Enlazaral propietario del archivo y escriba una ruta de acceso de clave de modelo de :

    Enlazar el nombre

  9. Seleccione la segunda etiqueta y, en el Inspectorde enlace, seleccione Enlazaral propietario del archivo y escriba una ruta de acceso de clave de modelo de :

    Enlace de la ocupación

  10. Guarde los cambios en el .xib archivo y vuelva a Visual Studio para sincronizar los cambios.

Edite EmployeeItemController.cs el archivo y haga que sea parecido al siguiente:

using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using AppKit;

namespace MacCollectionNew
{
    /// <summary>
    /// The Employee item controller handles the display of the individual items that will
    /// be displayed in the collection view as defined in the associated .XIB file.
    /// </summary>
    public partial class EmployeeItemController : NSCollectionViewItem
    {
        #region Private Variables
        /// <summary>
        /// The person that will be displayed.
        /// </summary>
        private PersonModel _person;
        #endregion

        #region Computed Properties
        // strongly typed view accessor
        public new EmployeeItem View
        {
            get
            {
                return (EmployeeItem)base.View;
            }
        }

        /// <summary>
        /// Gets or sets the person.
        /// </summary>
        /// <value>The person that this item belongs to.</value>
        [Export("Person")]
        public PersonModel Person
        {
            get { return _person; }
            set
            {
                WillChangeValue("Person");
                _person = value;
                DidChangeValue("Person");
            }
        }

        /// <summary>
        /// Gets or sets the color of the background for the item.
        /// </summary>
        /// <value>The color of the background.</value>
        public NSColor BackgroundColor {
            get { return Background.FillColor; }
            set { Background.FillColor = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="T:MacCollectionNew.EmployeeItemController"/> is selected.
        /// </summary>
        /// <value><c>true</c> if selected; otherwise, <c>false</c>.</value>
        /// <remarks>This also changes the background color based on the selected state
        /// of the item.</remarks>
        public override bool Selected
        {
            get
            {
                return base.Selected;
            }
            set
            {
                base.Selected = value;

                // Set background color based on the selection state
                if (value) {
                    BackgroundColor = NSColor.DarkGray;
                } else {
                    BackgroundColor = NSColor.LightGray;
                }
            }
        }
        #endregion

        #region Constructors
        // Called when created from unmanaged code
        public EmployeeItemController(IntPtr handle) : base(handle)
        {
            Initialize();
        }

        // Called when created directly from a XIB file
        [Export("initWithCoder:")]
        public EmployeeItemController(NSCoder coder) : base(coder)
        {
            Initialize();
        }

        // Call to load from the XIB/NIB file
        public EmployeeItemController() : base("EmployeeItem", NSBundle.MainBundle)
        {
            Initialize();
        }

        // Added to support loading from XIB/NIB
        public EmployeeItemController(string nibName, NSBundle nibBundle) : base(nibName, nibBundle) {

            Initialize();
        }

        // Shared initialization code
        void Initialize()
        {
        }
        #endregion
    }
}

Al consultar este código en detalle, la clase hereda de para que pueda actuar como NSCollectionViewItem prototipo de una celda de vista de colección. La propiedad expone la clase que se usó para enlazar datos a la Person vista de imágenes y etiquetas en Xcode. Se trata de una instancia del PersonModel objeto creado anteriormente.

La propiedad es un acceso directo al control que BackgroundColor se usará para mostrar el estado de selección de una NSBoxFillColor celda. Al invalidar la Selected propiedad de , el código siguiente establece o borra este estado de NSCollectionViewItem selección:

public override bool Selected
{
    get
    {
        return base.Selected;
    }
    set
    {
        base.Selected = value;

        // Set background color based on the selection state
        if (value) {
            BackgroundColor = NSColor.DarkGray;
        } else {
            BackgroundColor = NSColor.LightGray;
        }
    }
}

Crear el origen de datos de la vista de recopilación

Un origen de datos de vista de colección ( ) proporciona todos los datos de una vista de colección y crea y rellena una celda de vista de colección (mediante el prototipo) según sea necesario para cada elemento de NSCollectionViewDataSource.xib la colección.

Agregue una nueva clase al proyecto, llámela CollectionViewDataSource y haga que se parezca a la siguiente:

using System;
using System.Collections.Generic;
using AppKit;
using Foundation;

namespace MacCollectionNew
{
    /// <summary>
    /// Collection view data source provides the data for the collection view.
    /// </summary>
    public class CollectionViewDataSource : NSCollectionViewDataSource
    {
        #region Computed Properties
        /// <summary>
        /// Gets or sets the parent collection view.
        /// </summary>
        /// <value>The parent collection view.</value>
        public NSCollectionView ParentCollectionView { get; set; }

        /// <summary>
        /// Gets or sets the data that will be displayed in the collection.
        /// </summary>
        /// <value>A collection of PersonModel objects.</value>
        public List<PersonModel> Data { get; set; } = new List<PersonModel>();
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="T:MacCollectionNew.CollectionViewDataSource"/> class.
        /// </summary>
        /// <param name="parent">The parent collection that this datasource will provide data for.</param>
        public CollectionViewDataSource(NSCollectionView parent)
        {
            // Initialize
            ParentCollectionView = parent;

            // Attach to collection view
            parent.DataSource = this;

        }
        #endregion

        #region Override Methods
        /// <summary>
        /// Gets the number of sections.
        /// </summary>
        /// <returns>The number of sections.</returns>
        /// <param name="collectionView">The parent Collection view.</param>
        public override nint GetNumberOfSections(NSCollectionView collectionView)
        {
            // There is only one section in this view
            return 1;
        }

        /// <summary>
        /// Gets the number of items in the given section.
        /// </summary>
        /// <returns>The number of items.</returns>
        /// <param name="collectionView">The parent Collection view.</param>
        /// <param name="section">The Section number to count items for.</param>
        public override nint GetNumberofItems(NSCollectionView collectionView, nint section)
        {
            // Return the number of items
            return Data.Count;
        }

        /// <summary>
        /// Gets the item for the give section and item index.
        /// </summary>
        /// <returns>The item.</returns>
        /// <param name="collectionView">The parent Collection view.</param>
        /// <param name="indexPath">Index path specifying the section and index.</param>
        public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath)
        {
            var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
            item.Person = Data[(int)indexPath.Item];

            return item;
        }
        #endregion
    }
}

Al ver este código en detalle, la clase hereda de y expone una lista de NSCollectionViewDataSource instancias a través de su propiedad PersonModelData .

Puesto que esta colección solo tiene una sección, el código invalida el GetNumberOfSections método y siempre devuelve 1 . Además, el GetNumberofItems método se invalida cuando devuelve el número de elementos de la lista de Data propiedades.

Se GetItem llama al método siempre que se requiere una nueva celda y tiene un aspecto similar al siguiente:

public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath)
{
    var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
    item.Person = Data[(int)indexPath.Item];

    return item;
}

Se llama al método de la vista de colección para crear o devolver una instancia reutilizable de y su propiedad se establece en el elemento que se MakeItem muestra en la celda EmployeeItemControllerPerson solicitada.

Debe EmployeeItemController registrarse previamente con el controlador de vista de recopilación con el código siguiente:

EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");

El identificador ( ) utilizado en la llamada debe coincidir con el nombre del controlador de vistas que se MakeItem registró con la vista de colección. MakeItem Este paso se trata con detalle a continuación.

Control de la selección de elementos

Para controlar la selección y deselección de elementos de la colección, NSCollectionViewDelegate se requiere un . Puesto que en este ejemplo se va a usar el tipo de diseño integrado, se requiere una NSCollectionViewFlowLayout versión específica de este NSCollectionViewDelegateFlowLayout delegado.

Agregue una nueva clase al proyecto, llámela CollectionViewDelegate y haga que se parezca a la siguiente:

using System;
using Foundation;
using AppKit;

namespace MacCollectionNew
{
    /// <summary>
    /// Collection view delegate handles user interaction with the elements of the 
    /// collection view for the Flow-Based layout type.
    /// </summary>
    public class CollectionViewDelegate : NSCollectionViewDelegateFlowLayout
    {
        #region Computed Properties
        /// <summary>
        /// Gets or sets the parent view controller.
        /// </summary>
        /// <value>The parent view controller.</value>
        public ViewController ParentViewController { get; set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="T:MacCollectionNew.CollectionViewDelegate"/> class.
        /// </summary>
        /// <param name="parentViewController">Parent view controller.</param>
        public CollectionViewDelegate(ViewController parentViewController)
        {
            // Initialize
            ParentViewController = parentViewController;
        }
        #endregion

        #region Override Methods
        /// <summary>
        /// Handles one or more items being selected.
        /// </summary>
        /// <param name="collectionView">The parent Collection view.</param>
        /// <param name="indexPaths">The Index paths of the items being selected.</param>
        public override void ItemsSelected(NSCollectionView collectionView, NSSet indexPaths)
        {
            // Dereference path
            var paths = indexPaths.ToArray<NSIndexPath>();
            var index = (int)paths[0].Item;

            // Save the selected item
            ParentViewController.PersonSelected = ParentViewController.Datasource.Data[index];

        }

        /// <summary>
        /// Handles one or more items being deselected.
        /// </summary>
        /// <param name="collectionView">The parent Collection view.</param>
        /// <param name="indexPaths">The Index paths of the items being deselected.</param>
        public override void ItemsDeselected(NSCollectionView collectionView, NSSet indexPaths)
        {
            // Dereference path
            var paths = indexPaths.ToArray<NSIndexPath>();
            var index = paths[0].Item;

            // Clear selection
            ParentViewController.PersonSelected = null;
        }
        #endregion
    }
}

Los métodos y se reemplazan y se usan para establecer o borrar la propiedad del controlador de vistas que administra la vista de colección cuando el usuario selecciona o anula la selección ItemsSelectedItemsDeselected de un PersonSelected elemento. Esto se mostrará con detalle a continuación.

Creación de la vista de colección en Interface Builder

Con todas las piezas de compatibilidad necesarias, se puede editar el guión gráfico principal y agregar una vista de colección.

Haga lo siguiente:

  1. Haga doble clic en el archivo de la Explorador de soluciones para abrirlo para editarlo en la página Main.Storyboard de Xcode Main.Storyboard Interface Builder.

  2. Arrastre una vista de colección a la vista principal y cambie su tamaño para rellenar la vista:

    Agregar una vista de colección al diseño

  3. Con la vista de colección seleccionada, use el Editor de restricciones para anclarla a la vista cuando cambie de tamaño:

    Captura de pantalla que muestra Agregar nuevas restricciones.

  4. Asegúrese de que la vista de colección está seleccionada en el Superficie de diseño (y no la vista de desplazamiento bordeada o la vista de recorte que la contiene), cambie al Editor del asistente y cree una salida para la vista de colección:

    Captura de pantalla que muestra el Editor del asistente donde puede crear una salida.

  5. Guarde los cambios y vuelva a Visual Studio para sincronizar.

Reunirlo todo

Todas las piezas de soporte se han puesto ahora en su lugar con una clase para que actúe como el modelo de datos ( ), se ha agregado un elemento para proporcionar datos, se ha creado un elemento para controlar la selección de elementos y se ha agregado al guión gráfico principal y se ha expuesto como una salida PersonModelNSCollectionViewDataSource ( NSCollectionViewDelegateFlowLayoutNSCollectionViewEmployeeCollection ).

El último paso consiste en editar el controlador de vistas que contiene la vista de colección y reunir todas las partes para rellenar la colección y controlar la selección de elementos.

Edite ViewController.cs el archivo y haga que sea parecido al siguiente:

using System;
using AppKit;
using Foundation;
using CoreGraphics;

namespace MacCollectionNew
{
    /// <summary>
    /// The View controller controls the main view that houses the Collection View.
    /// </summary>
    public partial class ViewController : NSViewController
    {
        #region Private Variables
        private PersonModel _personSelected;
        private bool shouldEdit = true;
        #endregion

        #region Computed Properties
        /// <summary>
        /// Gets or sets the datasource that provides the data to display in the 
        /// Collection View.
        /// </summary>
        /// <value>The datasource.</value>
        public CollectionViewDataSource Datasource { get; set; }

        /// <summary>
        /// Gets or sets the person currently selected in the collection view.
        /// </summary>
        /// <value>The person selected or <c>null</c> if no person is selected.</value>
        [Export("PersonSelected")]
        public PersonModel PersonSelected
        {
            get { return _personSelected; }
            set
            {
                WillChangeValue("PersonSelected");
                _personSelected = value;
                DidChangeValue("PersonSelected");
                RaiseSelectionChanged();
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="T:MacCollectionNew.ViewController"/> class.
        /// </summary>
        /// <param name="handle">Handle.</param>
        public ViewController(IntPtr handle) : base(handle)
        {
        }
        #endregion

        #region Override Methods
        /// <summary>
        /// Called after the view has finished loading from the Storyboard to allow it to
        /// be configured before displaying to the user.
        /// </summary>
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // Initialize Collection View
            ConfigureCollectionView();
            PopulateWithData();
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Configures the collection view.
        /// </summary>
        private void ConfigureCollectionView()
        {
            EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");

            // Create a flow layout
            var flowLayout = new NSCollectionViewFlowLayout()
            {
                ItemSize = new CGSize(150, 150),
                SectionInset = new NSEdgeInsets(10, 10, 10, 20),
                MinimumInteritemSpacing = 10,
                MinimumLineSpacing = 10
            };
            EmployeeCollection.WantsLayer = true;

            // Setup collection view
            EmployeeCollection.CollectionViewLayout = flowLayout;
            EmployeeCollection.Delegate = new CollectionViewDelegate(this);

        }

        /// <summary>
        /// Populates the Datasource with data and attaches it to the collection view.
        /// </summary>
        private void PopulateWithData()
        {
            // Make datasource
            Datasource = new CollectionViewDataSource(EmployeeCollection);

            // Build list of employees
            Datasource.Data.Add(new PersonModel("Craig Dunn", "Documentation Manager", true));
            Datasource.Data.Add(new PersonModel("Amy Burns", "Technical Writer"));
            Datasource.Data.Add(new PersonModel("Joel Martinez", "Web & Infrastructure"));
            Datasource.Data.Add(new PersonModel("Kevin Mullins", "Technical Writer"));
            Datasource.Data.Add(new PersonModel("Mark McLemore", "Technical Writer"));
            Datasource.Data.Add(new PersonModel("Tom Opgenorth", "Technical Writer"));
            Datasource.Data.Add(new PersonModel("Larry O'Brien", "API Docs Manager", true));
            Datasource.Data.Add(new PersonModel("Mike Norman", "API Documentor"));

            // Populate collection view
            EmployeeCollection.ReloadData();
        }
        #endregion

        #region Events
        /// <summary>
        /// Selection changed delegate.
        /// </summary>
        public delegate void SelectionChangedDelegate();

        /// <summary>
        /// Occurs when selection changed.
        /// </summary>
        public event SelectionChangedDelegate SelectionChanged;

        /// <summary>
        /// Raises the selection changed event.
        /// </summary>
        internal void RaiseSelectionChanged() {
            // Inform caller
            if (this.SelectionChanged != null) SelectionChanged();
        }
        #endregion
    }
}

Si se observa este código en detalle, se define una propiedad para contener una instancia de que proporcionará los datos Datasource de la vista de CollectionViewDataSource colección. Se PersonSelected define una propiedad para contener el que representa el elemento seleccionado actualmente en la vista de PersonModel colección. Esta propiedad también genera el SelectionChanged evento cuando cambia la selección.

La clase se usa para registrar el controlador de vistas que actúa como prototipo de celda con la ConfigureCollectionView vista de colección mediante la línea siguiente:

EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");

Observe que el identificador ( ) utilizado para registrar el prototipo coincide con el que se llama en el método del definido GetItemCollectionViewDataSource anteriormente:

var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
...

Además, el tipo del controlador de vista debe coincidir con el nombre del archivo que define exactamente el prototipo. En el caso de este ejemplo, EmployeeItemController y EmployeeItemController.xib .

El diseño real de los elementos de la vista de colección se controla mediante una clase Collection View Layout y se puede cambiar dinámicamente en tiempo de ejecución mediante la asignación de una nueva instancia a la CollectionViewLayout propiedad . Al cambiar esta propiedad, se actualiza la apariencia de la vista de colección sin animar el cambio.

Apple incluye dos tipos de diseño integrados con la vista de colección que controlará los usos más típicos: NSCollectionViewFlowLayout y NSCollectionViewGridLayout . Si el desarrollador necesita un formato personalizado, como colocar los elementos en un círculo, puede crear una instancia personalizada de e invalidar los métodos necesarios para lograr el NSCollectionViewLayout efecto deseado.

En este ejemplo se usa el diseño de flujo predeterminado para crear una instancia de la clase y NSCollectionViewFlowLayout configurarla de la siguiente manera:

var flowLayout = new NSCollectionViewFlowLayout()
{
    ItemSize = new CGSize(150, 150),
    SectionInset = new NSEdgeInsets(10, 10, 10, 20),
    MinimumInteritemSpacing = 10,
    MinimumLineSpacing = 10
};

La ItemSize propiedad define el tamaño de cada celda individual de la colección. La propiedad define los conjuntos del borde de la colección en los que se colocarán SectionInset las celdas. MinimumInteritemSpacing define el espaciado mínimo entre los elementos y MinimumLineSpacing define el espaciado mínimo entre las líneas de la colección.

El diseño se asigna a la vista de colección y se adjunta una instancia de CollectionViewDelegate para controlar la selección de elementos:

// Setup collection view
EmployeeCollection.CollectionViewLayout = flowLayout;
EmployeeCollection.Delegate = new CollectionViewDelegate(this);

El método crea una nueva instancia de , la rellena con datos, la adjunta a la vista de colección y llama al método para PopulateWithDataCollectionViewDataSource mostrar los ReloadData elementos:

private void PopulateWithData()
{
    // Make datasource
    Datasource = new CollectionViewDataSource(EmployeeCollection);

    // Build list of employees
    Datasource.Data.Add(new PersonModel("Craig Dunn", "Documentation Manager", true));
    ...

    // Populate collection view
    EmployeeCollection.ReloadData();
}

El ViewDidLoad método se invalida y llama a los ConfigureCollectionViewPopulateWithData métodos y para mostrar la vista de colección final al usuario:

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    // Initialize Collection View
    ConfigureCollectionView();
    PopulateWithData();
}

Resumen

En este artículo se ha detallado cómo trabajar con vistas de colección en una aplicación de Xamarin.Mac. En primer lugar, se ha visto la exposición de una clase de C# a mediante Key-Value Objective-C Coding (KVC) y Key-Value Observing (KVO). A continuación, se mostró cómo usar una clase compatible con KVO y enlazarla a vistas de colección en el Interface Builder de Xcode. Por último, mostró cómo interactuar con vistas de colección en código de C#.