Condividi tramite


Visualizzazioni raccolta in Xamarin.Mac

Questo articolo descrive l'uso delle visualizzazioni della raccolta in un'app Xamarin.Mac. Vengono illustrate la creazione e la gestione delle visualizzazioni di raccolta in Xcode e Interface Builder e l'uso a livello di codice.

Quando si lavora con C# e .NET in un'app Xamarin.Mac, lo sviluppatore ha accesso agli stessi controlli visualizzazione raccolta AppKit che uno sviluppatore lavora in Objective-C e Xcode . Poiché Xamarin.Mac si integra direttamente con Xcode, lo sviluppatore usa Interface Builder di Xcode per creare e gestire visualizzazioni della raccolta.

Un NSCollectionView oggetto visualizza una griglia di visualizzazioni secondarie organizzate usando un oggetto NSCollectionViewLayout. Ogni visualizzazione secondaria nella griglia è rappresentata da un oggetto NSCollectionViewItem che gestisce il caricamento del contenuto della visualizzazione da un .xib file.

Esecuzione di un'app di esempio

Questo articolo illustra le nozioni di base sull'uso delle visualizzazioni della raccolta in un'app Xamarin.Mac. È consigliabile usare prima di tutto l'articolo Hello, Mac , in particolare le sezioni Introduzione a Xcode e Interface Builder e Outlet e Actions , in quanto illustra i concetti e le tecniche chiave usati in questo articolo.

È possibile esaminare anche la sezione Esposizione di classi/metodi C# alObjective-Cdocumento Internals di Xamarin.Mac, che illustra anche i Register comandi e Export usati per collegare le classi C# agli oggetti e agli Objective-C elementi dell'interfaccia utente.

Informazioni sulle visualizzazioni della raccolta

L'obiettivo principale di una visualizzazione raccolta (NSCollectionView) è disporre visivamente un gruppo di oggetti in modo organizzato usando un layout visualizzazione raccolta (), con ogni singolo oggetto (NSCollectionViewLayoutNSCollectionViewItem) ottenendo la propria visualizzazione nell'insieme più grande. Le visualizzazioni della raccolta funzionano tramite tecniche di data binding e codifica chiave-valore e, di conseguenza, è necessario leggere la documentazione sul data binding e sulla codifica chiave-valore prima di continuare con questo articolo.

La visualizzazione raccolta non dispone di un elemento di visualizzazione raccolta predefinito standard (ad esempio una visualizzazione struttura o tabella), quindi lo sviluppatore è responsabile della progettazione e dell'implementazione di una visualizzazione prototipo usando altri controlli AppKit, ad esempio Campi immagine, Campi di testo, Etichette e così via. Questa visualizzazione prototipo verrà usata per visualizzare e utilizzare ogni elemento gestito dalla visualizzazione Raccolta e viene archiviato in un .xib file.

Poiché lo sviluppatore è responsabile dell'aspetto di un elemento visualizzazione raccolta, la visualizzazione raccolta non supporta l'evidenziazione di un elemento selezionato nella griglia. L'implementazione di questa funzionalità verrà illustrata in questo articolo.

Definizione del modello di dati

Prima di data binding di una visualizzazione raccolta in Interface Builder, è necessario definire una classe conforme a Key-Value Coding (KVC)/Key-Value Observing (KVO) nell'app Xamarin.Mac per fungere da modello di dati per l'associazione. Il modello di dati fornisce tutti i dati che verranno visualizzati nella raccolta e riceve tutte le modifiche apportate dall'utente nell'interfaccia utente durante l'esecuzione dell'applicazione.

Si prenda l'esempio di un'app che gestisce un gruppo di dipendenti, è possibile usare la classe seguente per definire il modello di dati:

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
    }
}

Il PersonModel modello di dati verrà usato nel resto di questo articolo.

Utilizzo di una visualizzazione raccolta

Il data binding con una visualizzazione raccolta è molto simile all'associazione con una vista tabella, come NSCollectionViewDataSource viene usato per fornire dati per la raccolta. Poiché la visualizzazione raccolta non ha un formato di visualizzazione predefinito, è necessario più lavoro per fornire commenti e suggerimenti sull'interazione dell'utente e tenere traccia della selezione dell'utente.

Creazione del prototipo di cella

Poiché la visualizzazione raccolta non include un prototipo di cella predefinito, lo sviluppatore dovrà aggiungere uno o più .xib file all'app Xamarin.Mac per definire il layout e il contenuto delle singole celle.

Effettua le operazioni seguenti:

  1. Nella Esplora soluzioni fare clic con il pulsante destro del mouse sul nome del progetto e scegliere Aggiungi>nuovo file...

  2. Selezionare Il controller di visualizzazione Mac>, assegnare un nome (ad esempio EmployeeItem in questo esempio) e fare clic sul pulsante Nuovo per creare:

    Aggiunta di un nuovo controller di visualizzazione

    Verrà aggiunto un EmployeeItem.csfile e EmployeeItemController.csEmployeeItemController.xib alla soluzione del progetto.

  3. Fare doppio clic sul EmployeeItemController.xib file per aprirlo per la modifica in Interface Builder di Xcode.

  4. Aggiungere un NSBoxcontrollo e NSImageView due NSLabel controlli alla visualizzazione e disporre i controlli come indicato di seguito:

    Progettazione del layout del prototipo di cella

  5. Aprire l'Editor assistente e creare un outlet per in NSBox modo che possa essere utilizzato per indicare lo stato di selezione di una cella:

    Esposizione del NSBox in un outlet

  6. Tornare all'editor standard e selezionare la visualizzazione immagini.

  7. In Controllo associazione selezionare Associa al>proprietario del file e immettere un percorso chiave modello di :self.Person.Icon

    Associazione dell'icona

  8. Selezionare la prima etichetta e in Controllo associazione selezionare Associa al>proprietario del file e immettere un percorso chiave modello di :self.Person.Name

    Associazione del nome

  9. Selezionare la seconda etichetta e in Controllo associazione selezionare Associa al>proprietario del file e immettere un percorso chiave modello di :self.Person.Occupation

    Associazione dell'occupazione

  10. Salvare le modifiche apportate al .xib file e tornare a Visual Studio per sincronizzare le modifiche.

Modificare il EmployeeItemController.cs file e renderlo simile al seguente:

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
    }
}

Esaminando in dettaglio questo codice, la classe eredita da NSCollectionViewItem in modo che possa fungere da prototipo per una cella Di visualizzazione raccolta. La Person proprietà espone la classe utilizzata per l'associazione di dati alla visualizzazione immagini e alle etichette in Xcode. Si tratta di un'istanza dell'oggetto PersonModel creato in precedenza.

La BackgroundColor proprietà è un collegamento al NSBox controllo FillColor che verrà utilizzato per visualizzare lo stato di selezione di una cella. Eseguendo l'override NSCollectionViewItemdella Selected proprietà di , il codice seguente imposta o cancella questo stato di selezione:

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;
        }
    }
}

Creazione dell'origine dati vista raccolta

Un'origine dati visualizzazione raccolta (NSCollectionViewDataSource) fornisce tutti i dati per una visualizzazione raccolta e crea e popola una cella di visualizzazione raccolta (usando il .xib prototipo) come richiesto per ogni elemento della raccolta.

Aggiungere una nuova classe al progetto, chiamarla CollectionViewDataSource e renderla simile alla seguente:

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
    }
}

Esaminando in dettaglio questo codice, la classe eredita da NSCollectionViewDataSource ed espone un elenco di PersonModel istanze tramite la relativa Data proprietà .

Poiché questa raccolta ha una sola sezione, il codice esegue l'override del GetNumberOfSections metodo e restituisce 1sempre . Inoltre, il GetNumberofItems metodo viene sottoposto a override in corrispondenza del quale restituisce il numero di elementi nell'elenco Data delle proprietà.

Il GetItem metodo viene chiamato ogni volta che è necessaria una nuova cella e ha un aspetto simile al seguente:

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

    return item;
}

Il MakeItem metodo della visualizzazione raccolta viene chiamato per creare o restituire un'istanza riutilizzabile di EmployeeItemController e la relativa Person proprietà è impostata su elemento visualizzato nella cella richiesta.

Deve EmployeeItemController essere registrato in precedenza con il controller di visualizzazione raccolta usando il codice seguente:

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

L'identificatore (EmployeeCell) utilizzato nella MakeItem chiamata deve corrispondere al nome del controller di visualizzazione registrato con la visualizzazione raccolta. Questo passaggio verrà illustrato in dettaglio di seguito.

Gestione della selezione degli elementi

Per gestire la selezione e la deselezionazione degli elementi nella raccolta, sarà necessario un oggetto NSCollectionViewDelegate . Poiché questo esempio usa il tipo di layout predefinito NSCollectionViewFlowLayout , sarà necessaria una NSCollectionViewDelegateFlowLayout versione specifica di questo delegato.

Aggiungere una nuova classe al progetto, chiamarla CollectionViewDelegate e renderla simile alla seguente:

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
    }
}

I ItemsSelected metodi e ItemsDeselected vengono sottoposti a override e utilizzati per impostare o cancellare la PersonSelected proprietà del controller di visualizzazione che gestisce la visualizzazione raccolta quando l'utente seleziona o deseleziona un elemento. Questa operazione verrà illustrata in dettaglio di seguito.

Creazione della visualizzazione raccolta in Interface Builder

Con tutti i componenti di supporto necessari, è possibile modificare lo storyboard principale e aggiungervi una visualizzazione raccolta.

Effettua le operazioni seguenti:

  1. Fare doppio clic sul Main.Storyboard file nel Esplora soluzioni per aprirlo per la modifica in Interface Builder di Xcode.

  2. Trascinare una visualizzazione raccolta nella visualizzazione principale e ridimensionarla per riempire la visualizzazione:

    Aggiunta di una visualizzazione raccolta al layout

  3. Con l'opzione Visualizzazione raccolta selezionata, usare l'Editor vincoli per aggiungerla alla visualizzazione quando viene ridimensionata:

    Screenshot che mostra l'opzione Aggiungi nuovi vincoli.

  4. Assicurarsi che l'opzione Visualizzazione raccolta sia selezionata nell'area di progettazione (e non nella visualizzazione a scorrimento con bordi o clip che lo contiene), passare all'Editorassistente e creare un outlet per la visualizzazione raccolta:

    Screenshot che mostra l'Editor assistente in cui è possibile creare un outlet.

  5. Salvare le modifiche e tornare a Visual Studio per la sincronizzazione.

Riunire tutto insieme

Tutti i componenti di supporto sono ora stati inseriti con una classe che funge da modello di dati (PersonModel), è stato aggiunto un NSCollectionViewDataSource oggetto per fornire i dati, è stato creato un NSCollectionViewDelegateFlowLayout oggetto per gestire la selezione degli elementi e un NSCollectionView oggetto è stato aggiunto allo Storyboard principale ed esposto come outlet (EmployeeCollection).

Il passaggio finale consiste nel modificare il controller di visualizzazione che contiene la visualizzazione raccolta e riunire tutte le parti per popolare la raccolta e gestire la selezione degli elementi.

Modificare il ViewController.cs file e renderlo simile al seguente:

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
    }
}

Esaminando in dettaglio questo codice, viene definita una Datasource proprietà per contenere un'istanza CollectionViewDataSource di che fornirà i dati per la visualizzazione raccolta. Una PersonSelected proprietà è definita per contenere l'oggetto PersonModel che rappresenta l'elemento attualmente selezionato nella visualizzazione Raccolta. Questa proprietà genera anche l'evento SelectionChanged quando cambia la selezione.

La ConfigureCollectionView classe viene usata per registrare il controller di visualizzazione che funge da prototipo di cella con la visualizzazione raccolta usando la riga seguente:

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

Si noti che l'identificatore (EmployeeCell) usato per registrare il prototipo corrisponde a quello chiamato nel GetItem metodo dell'oggetto CollectionViewDataSource precedente definito:

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

Inoltre, il tipo del controller di visualizzazione deve corrispondere al nome del .xib file che definisce esattamente il prototipo. Nel caso di questo esempio e EmployeeItemControllerEmployeeItemController.xib.

Il layout effettivo degli elementi nella visualizzazione raccolta è controllato da una classe Collection View Layout e può essere modificato in modo dinamico in fase di esecuzione assegnando una nuova istanza alla CollectionViewLayout proprietà . La modifica di questa proprietà aggiorna l'aspetto della visualizzazione raccolta senza animare la modifica.

Apple offre due tipi di layout predefiniti con la Visualizzazione raccolta che gestirà gli usi più tipici: NSCollectionViewFlowLayout e NSCollectionViewGridLayout. Se lo sviluppatore ha richiesto un formato personalizzato, ad esempio la disposizione degli elementi in un cerchio, può creare un'istanza personalizzata di NSCollectionViewLayout ed eseguire l'override dei metodi necessari per ottenere l'effetto desiderato.

Questo esempio usa il layout del flusso predefinito in modo che crei un'istanza della NSCollectionViewFlowLayout classe e la configuri come indicato di seguito:

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

La ItemSize proprietà definisce le dimensioni di ogni singola cella dell'insieme. La SectionInset proprietà definisce gli inset dal bordo dell'insieme in cui verranno disposte le celle. MinimumInteritemSpacing definisce la spaziatura minima tra gli elementi e MinimumLineSpacing definisce la spaziatura minima tra le righe della raccolta.

Il layout viene assegnato alla visualizzazione raccolta e un'istanza CollectionViewDelegate di è associata per gestire la selezione degli elementi:

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

Il PopulateWithData metodo crea una nuova istanza di CollectionViewDataSource, lo popola con i dati, lo collega alla visualizzazione raccolta e chiama il ReloadData metodo per visualizzare gli elementi:

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();
}

Il ViewDidLoad metodo viene sottoposto a override e chiama i ConfigureCollectionView metodi e PopulateWithData per visualizzare la visualizzazione raccolta finale all'utente:

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

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

Riepilogo

Questo articolo ha esaminato in dettaglio l'uso delle visualizzazioni della raccolta in un'applicazione Xamarin.Mac. In primo luogo, ha esaminato l'esposizione di una classe C# a Objective-C usando la codifica chiave-valore (KVC) e l'osservazione chiave-valore (KVO). Successivamente, è stato illustrato come usare una classe conforme KVO e Data Bind it to Collection Views in Interface Builder di Xcode. Infine, ha illustrato come interagire con le viste della raccolta nel codice C#.