Sammlungsansichten in Xamarin.Mac

In diesem Artikel wird das Arbeiten mit Sammlungsansichten in einer Xamarin.Mac-App beschrieben. Es behandelt das Erstellen und Verwalten von Sammlungsansichten in Xcode und Interface Builder sowie das programmgesteuerte Arbeiten mit ihnen.

Bei der Arbeit mit C# und .NET in einer Xamarin.Mac-App hat der Entwickler Zugriff auf die gleichen AppKit-Sammlungsansichtssteuerelemente wie ein Entwickler, der in Objective-C und Xcode arbeitet. Da Xamarin.Mac direkt in Xcode integriert wird, verwendet der Entwickler den Schnittstellen-Generator von Xcode, um Sammlungsansichten zu erstellen und zu verwalten.

Ein NSCollectionView zeigt ein Raster von Unteransichten an, die mithilfe eines NSCollectionViewLayoutorganisiert sind. Jede Unteransicht im Raster wird durch eine NSCollectionViewItem dargestellt, die das Laden des Ansichtsinhalts aus einer .xib Datei verwaltet.

Beispiel für eine App-Ausführung

In diesem Artikel werden die Grundlagen der Arbeit mit Sammlungsansichten in einer Xamarin.Mac-App behandelt. Es wird dringend empfohlen, dass Sie zuerst den Artikel Hello, Mac durcharbeiten, insbesondere die Abschnitte Einführung in Xcode und Interface Builder sowie Outlets und Aktionen , da er die wichtigsten Konzepte und Techniken behandelt, die in diesem Artikel verwendet werden.

Möglicherweise sollten Sie auch einen Blick auf den Abschnitt Verfügbarmachen von C#-Klassen/-Methoden für Objective-C das Xamarin.Mac Internals-Dokument werfen. Darin werden die Befehle und Export erläutert, die Register zum Verknüpfen Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.

Informationen zu Sammlungsansichten

Das Standard Ziel einer Sammlungsansicht (NSCollectionView) besteht darin, eine Gruppe von Objekten mithilfe eines Sammlungsansichtslayouts (NSCollectionViewLayout) visuell organisiert anzuordnen, wobei jedes einzelne Objekt (NSCollectionViewItem) eine eigene Ansicht in der größeren Auflistung erhält. Sammlungsansichten funktionieren über Datenbindungs- und Key-Value Codierungstechniken. Daher sollten Sie die Dokumentation zur Datenbindung und Key-Value Codierung lesen, bevor Sie mit diesem Artikel fortfahren.

Die Sammlungsansicht verfügt über kein standardmäßiges integriertes Sammlungsansichtselement (wie eine Gliederungs- oder Tabellenansicht), sodass der Entwickler für das Entwerfen und Implementieren einer Prototypansicht mit anderen AppKit-Steuerelementen wie Bildfeldern, Textfeldern, Bezeichnungen usw. verantwortlich ist. Diese Prototypansicht wird zum Anzeigen und Arbeiten mit jedem Element verwendet, das von der Sammlungsansicht verwaltet wird, und wird in einer .xib Datei gespeichert.

Da der Entwickler für das Aussehen und Verhalten eines Sammlungsansichtselements verantwortlich ist, verfügt die Sammlungsansicht über keine integrierte Unterstützung für die Hervorhebung eines ausgewählten Elements im Raster. Die Implementierung dieses Features wird in diesem Artikel behandelt.

Definieren des Datenmodells

Vor der Datenbindung einer Sammlungsansicht im Schnittstellen-Generator muss in der Xamarin.Mac-App eine KVO-kompatible Klasse (Key-Value Coding)/Key-Value Observing (KVO) definiert werden, um als Datenmodell für die Bindung zu fungieren. Das Datenmodell stellt alle Daten bereit, die in der Sammlung angezeigt werden, und empfängt alle Änderungen an den Daten, die der Benutzer während der Ausführung der Anwendung auf der Benutzeroberfläche vornimmt.

Nehmen wir das Beispiel einer App, die eine Gruppe von Mitarbeitern verwaltet. Die folgende Klasse könnte zum Definieren des Datenmodells verwendet werden:

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

Das PersonModel Datenmodell wird im weiteren Verlauf dieses Artikels verwendet.

Arbeiten mit einer Sammlungsansicht

Die Datenbindung mit einer Sammlungsansicht ähnelt der Bindung mit einer Tabellenansicht, da NSCollectionViewDataSource sie zum Bereitstellen von Daten für die Sammlung verwendet wird. Da die Sammlungsansicht kein voreingestelltes Anzeigeformat aufweist, ist mehr Arbeit erforderlich, um Feedback zu Benutzerinteraktionen bereitzustellen und die Benutzerauswahl nachzuverfolgen.

Erstellen des Zellprototyps

Da die Sammlungsansicht keinen Standardzellenprototyp enthält, muss der Entwickler der Xamarin.Mac-App eine oder .xib mehrere Dateien hinzufügen, um das Layout und den Inhalt der einzelnen Zellen zu definieren.

Gehen Sie folgendermaßen vor:

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie Neue Datei hinzufügen>... aus.

  2. Wählen Sie Mac>View Controller aus, geben Sie ihm einen Namen (wie EmployeeItem in diesem Beispiel), und klicken Sie zum Erstellen auf die Schaltfläche Neu :

    Hinzufügen eines neuen Ansichtscontrollers

    Dadurch werden der Projektmappe eine EmployeeItem.csEmployeeItemController.cs - und EmployeeItemController.xib -Datei hinzugefügt.

  3. Doppelklicken Sie auf die EmployeeItemController.xib Datei, um sie zur Bearbeitung im Interface Builder von Xcode zu öffnen.

  4. Fügen Sie der Ansicht ein NSBox- NSImageView und zwei NSLabel -Steuerelemente hinzu, und legen Sie sie wie folgt aus:

    Entwerfen des Layouts des Zellenprototyps

  5. Öffnen Sie den Assistenten-Editor , und erstellen Sie ein Outlet für das NSBox , damit er verwendet werden kann, um den Auswahlstatus einer Zelle anzugeben:

    Verfügbarmachen der NSBox in einer Steckdose

  6. Kehren Sie zum Standard-Editor zurück , und wählen Sie die Bildansicht aus.

  7. Wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von einself.Person.Icon:

    Binden des Symbols

  8. Wählen Sie die erste Bezeichnung aus, und wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von einself.Person.Name:

    Binden des Namens

  9. Wählen Sie die zweite Bezeichnung aus, und wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von einself.Person.Occupation:

    Bindung des Berufes

  10. Speichern Sie die Änderungen an der .xib Datei, und kehren Sie zu Visual Studio zurück, um die Änderungen zu synchronisieren.

Bearbeiten Sie die EmployeeItemController.cs Datei, und lassen Sie sie wie folgt aussehen:

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

Wenn Sie sich diesen Code im Detail ansehen, erbt die -Klasse von NSCollectionViewItem , sodass sie als Prototyp für eine Sammlungsansichtszelle fungieren kann. Die Person -Eigenschaft macht die -Klasse verfügbar, die zum Binden von Daten an die Bildansicht und Bezeichnungen in Xcode verwendet wurde. Dies ist eine instance der PersonModel oben erstellten.

Die BackgroundColor -Eigenschaft ist eine Verknüpfung zu den NSBox SteuerelementenFillColor, die verwendet wird, um die Auswahl status einer Zelle anzuzeigen. Durch Überschreiben der Selected -Eigenschaft von NSCollectionViewItemwird dieser Auswahlzustand durch den folgenden Code festgelegt oder gelöscht:

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

Erstellen der Datenquelle für die Sammlungsansicht

Eine Sammlungsansicht-Datenquelle (NSCollectionViewDataSource) stellt alle Daten für eine Sammlungsansicht bereit und erstellt und füllt eine Sammlungsansichtszelle (unter Verwendung des .xib Prototyps) nach Bedarf für jedes Element in der Auflistung.

Fügen Sie dem Projekt eine neue Klasse hinzu, rufen Sie sie CollectionViewDataSource auf, und lassen Sie sie wie folgt aussehen:

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

Wenn Sie diesen Code im Detail betrachten, erbt die -Klasse von NSCollectionViewDataSource und macht eine Liste von PersonModel Instanzen über ihre Data -Eigenschaft verfügbar.

Da diese Auflistung nur über einen Abschnitt verfügt, überschreibt der Code die GetNumberOfSections -Methode und gibt immer zurück 1. Darüber hinaus wird die GetNumberofItems -Methode bei überschrieben, sie gibt die Anzahl der Elemente in der Data Eigenschaftenliste zurück.

Die GetItem -Methode wird immer dann aufgerufen, wenn eine neue Zelle erforderlich ist, und sieht wie folgt aus:

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

    return item;
}

Die MakeItem -Methode der Sammlungsansicht wird aufgerufen, um eine wiederverwendbare instance des zu erstellen oder zurückzugeben, und die EmployeeItemControllerPerson -Eigenschaft wird auf das Element festgelegt, das in der angeforderten Zelle angezeigt wird.

Muss EmployeeItemController zuvor mit dem folgenden Code beim Sammlungsansichtscontroller registriert werden:

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

Der im MakeItem Aufruf verwendete Bezeichner (EmployeeCell) muss mit dem Namen des Ansichtscontrollers übereinstimmen, der in der Sammlungsansicht registriert wurde. Dieser Schritt wird unten ausführlich behandelt.

Behandeln der Elementauswahl

Um die Auswahl und Abwahl von Elementen in der Auflistung zu behandeln, ist ein NSCollectionViewDelegate erforderlich. Da in diesem Beispiel der integrierte NSCollectionViewFlowLayout Layouttyp verwendet wird, ist eine NSCollectionViewDelegateFlowLayout bestimmte Version dieses Delegaten erforderlich.

Fügen Sie dem Projekt eine neue Klasse hinzu, rufen Sie sie CollectionViewDelegate auf, und lassen Sie sie wie folgt aussehen:

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

Die ItemsSelected Methoden und ItemsDeselected werden überschrieben und verwendet, um die PersonSelected Eigenschaft des Ansichtscontrollers festzulegen oder zu löschen, der die Sammlungsansicht behandelt, wenn der Benutzer ein Element auswählt oder deaktiviert. Dies wird unten im Detail gezeigt.

Erstellen der Sammlungsansicht im Schnittstellen-Generator

Wenn alle erforderlichen unterstützenden Elemente vorhanden sind, kann das Standard Storyboard bearbeitet und eine Sammlungsansicht hinzugefügt werden.

Gehen Sie folgendermaßen vor:

  1. Doppelklicken Sie im Projektmappen-Explorer auf die Main.Storyboard Datei, um sie zur Bearbeitung im Xcode-Schnittstellen-Generator zu öffnen.

  2. Ziehen Sie eine Sammlungsansicht in die Hauptansicht, und ändern Sie ihre Größe, um die Ansicht auszufüllen:

    Hinzufügen einer Sammlungsansicht zum Layout

  3. Wenn die Sammlungsansicht ausgewählt ist, verwenden Sie den Einschränkungs-Editor, um sie an die Ansicht anzuheften, wenn die Größe geändert wird:

    Screenshot: Hinzufügen neuer Einschränkungen

  4. Stellen Sie sicher, dass die Sammlungsansicht auf der Entwurfsoberfläche ausgewählt ist (und nicht die umrandete Bildlaufansicht oder die Clip-Ansicht , die sie enthält), wechseln Sie zum Assistenten-Editor , und erstellen Sie einen Ausgang für die Sammlungsansicht:

    Screenshot des Assistenten-Editors, in dem Sie ein Outlet erstellen können.

  5. Speichern Sie die Änderungen, und kehren Sie zur Synchronisierung zu Visual Studio zurück.

Alles zusammenführen

Alle unterstützenden Teile wurden nun mit einer Klasse eingerichtet, die als Datenmodell () fungiert,PersonModel wurde hinzugefügt NSCollectionViewDataSource , um Daten zu liefern, ein NSCollectionViewDelegateFlowLayout wurde erstellt, um die Elementauswahl zu behandeln, und ein NSCollectionView wurde dem Main Storyboard hinzugefügt und als Outlet (EmployeeCollection) verfügbar gemacht.

Der letzte Schritt besteht darin, den Ansichtscontroller zu bearbeiten, der die Sammlungsansicht enthält, und alle Teile zusammenzuführen, um die Sammlungs- und Behandlungselementauswahl aufzufüllen.

Bearbeiten Sie die ViewController.cs Datei, und lassen Sie sie wie folgt aussehen:

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

Wenn Sie sich diesen Code im Detail ansehen, wird eine Datasource Eigenschaft definiert, um eine instance der zu enthalten, die CollectionViewDataSource die Daten für die Sammlungsansicht bereitstellt. Eine PersonSelected -Eigenschaft ist definiert, um das zu enthalten, das PersonModel das aktuell ausgewählte Element in der Sammlungsansicht darstellt. Diese Eigenschaft löst auch das SelectionChanged -Ereignis aus, wenn sich die Auswahl ändert.

Die ConfigureCollectionView -Klasse wird verwendet, um den Ansichtscontroller zu registrieren, der als Zellprototyp mit der Sammlungsansicht fungiert, indem die folgende Zeile verwendet wird:

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

Beachten Sie, dass der Bezeichner (EmployeeCell), der zum Registrieren des Prototyps verwendet wird, mit dem in der GetItem oben definierten CollectionViewDataSource Methode aufgerufen wird:

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

Darüber hinaus muss der Typ des Ansichtscontrollers mit dem Namen der .xib Datei übereinstimmen, die den Prototyp genau definiert. Im Fall dieses Beispiels EmployeeItemController und EmployeeItemController.xib.

Das tatsächliche Layout der Elemente in der Sammlungsansicht wird von einer Layoutklasse der Sammlungsansicht gesteuert und kann zur Laufzeit dynamisch geändert werden, indem der Eigenschaft ein neuer instance zugewiesen CollectionViewLayout wird. Wenn Sie diese Eigenschaft ändern, wird die Darstellung der Sammlungsansicht aktualisiert, ohne die Änderung zu animieren.

Apple liefert zwei integrierte Layouttypen mit der Sammlungsansicht, die die meisten typischen Verwendungen übernimmt: NSCollectionViewFlowLayout und NSCollectionViewGridLayout. Wenn der Entwickler ein benutzerdefiniertes Format benötigt, z. B. das Auslegen der Elemente in einem Kreis, kann er eine benutzerdefinierte instance von NSCollectionViewLayout erstellen und die erforderlichen Methoden überschreiben, um den gewünschten Effekt zu erzielen.

In diesem Beispiel wird das Standardflowlayout verwendet, sodass eine instance der NSCollectionViewFlowLayout -Klasse erstellt und wie folgt konfiguriert wird:

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

Die ItemSize -Eigenschaft definiert die Größe jeder einzelnen Zelle in der Auflistung. Die SectionInset -Eigenschaft definiert die Einsets vom Rand der Auflistung, in der Zellen angeordnet werden. MinimumInteritemSpacing definiert den Mindestabstand zwischen Elementen und MinimumLineSpacing definiert den Mindestabstand zwischen Zeilen in der Auflistung.

Das Layout ist der Sammlungsansicht zugewiesen, und eine instance der ist angefügt, um die CollectionViewDelegate Elementauswahl zu behandeln:

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

Die PopulateWithData -Methode erstellt eine neue instance von CollectionViewDataSource, füllt sie mit Daten auf, fügt sie an die Sammlungsansicht an und ruft die ReloadData -Methode auf, um die Elemente anzuzeigen:

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

Die ViewDidLoad -Methode wird überschrieben und ruft die ConfigureCollectionView Methoden und PopulateWithData auf, um dem Benutzer die endgültige Sammlungsansicht anzuzeigen:

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

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

Zusammenfassung

In diesem Artikel wird die Arbeit mit Sammlungsansichten in einer Xamarin.Mac-Anwendung ausführlich erläutert. Zunächst wurde das Verfügbarmachen einer C#-Klasse Objective-C mithilfe von Key-Value Coding (KVC) und Key-Value Observing (KVO) untersucht. Als Nächstes wurde gezeigt, wie Sie eine KVO-kompatible Klasse verwenden und sie an Sammlungsansichten im Xcode-Schnittstellen-Generator binden. Schließlich wurde gezeigt, wie Sie mit Sammlungsansichten in C#-Code interagieren.