Sammlungsansichten in Xamarin.Mac

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

Beim Arbeiten mit C# und .NET in einer Xamarin.Mac-App hat der Entwickler Zugriff auf die gleichen AppKit-Sammlungsansichtssteuerelemente, in Objective-C denen ein Entwickler arbeitet und Xcode ausführt. Da Xamarin.Mac direkt in Xcode integriert wird, verwendet der Entwickler den Schnittstellen-Generator von Xcode zum Erstellen und Standard tain-Sammlungsansichten.

A NSCollectionView displays a grid of subviews organized using a NSCollectionViewLayout. Jede Unteransicht im Raster wird durch eine NSCollectionViewItem Darstellung dargestellt, die das Laden des Inhalts der Ansicht 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 " und "Outlets" und "Actions ", da sie wichtige Konzepte und Techniken behandelt, die in diesem Artikel verwendet werden.

Möglicherweise möchten Sie sich auch die Verfügbarmachen von C#-Klassen /-Methoden imObjective-CAbschnitt des Xamarin.Mac Internals-Dokuments ansehen, und es werden die befehle Export erläutert, die Register zum Verketten 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 () visuell anzuordnen, wobei jedes einzelne Objekt (NSCollectionViewLayoutNSCollectionViewItem) seine eigene Ansicht in der größeren Auflistung erhält. Sammlungsansichten funktionieren über Datenbindungs- und Schlüsselwertcodierungstechniken. Daher sollten Sie die Dokumentation "Datenbindung" und "Key-Value Coding " lesen, bevor Sie mit diesem Artikel fortfahren.

Die Sammlungsansicht verfügt über kein standardmäßiges, integriertes Sammlungsansichtselement (z. B. eine Gliederungs- oder Tabellenansicht), sodass der Entwickler für das Entwerfen und Implementieren einer Prototypansicht mithilfe anderer AppKit-Steuerelemente wie Bildfelder, Textfelder, Bezeichnungen usw. verantwortlich ist. Diese Prototypansicht wird verwendet, um jedes Element anzuzeigen und zu arbeiten, das von der Sammlungsansicht verwaltet wird und in einer .xib Datei gespeichert wird.

Da der Entwickler für das Aussehen und Verhalten eines Sammlungsansichtselements verantwortlich ist, bietet die Sammlungsansicht keine integrierte Unterstützung zum Hervorheben 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 eine KVC-kompatible Klasse (Key-Value Coding)/Key-Value Observing (KVO) in der Xamarin.Mac-App 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 in der Benutzeroberfläche während der Ausführung der Anwendung vornimmt.

Nehmen Sie sich das Beispiel einer App, die eine Gruppe von Mitarbeitern verwaltet, die folgende Klasse zum Definieren des Datenmodells verwendet werden kann:

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 während des restlichen Artikels verwendet.

Arbeiten mit einer Sammlungsansicht

Die Datenbindung mit einer Sammlungsansicht ähnelt der Bindung mit einer Tabellenansicht, wie NSCollectionViewDataSource sie zum Bereitstellen von Daten für die Sammlung verwendet wird. Da die Sammlungsansicht nicht über ein voreingestelltes Anzeigeformat verfügt, ist mehr Arbeit erforderlich, um Feedback zur Benutzerinteraktion bereitzustellen und die Benutzerauswahl nachzuverfolgen.

Erstellen des Zellprototyps

Da die Sammlungsansicht keinen Standardzellenprototyp enthält, muss der Entwickler der Xamarin.Mac-App mindestens eine .xib Datei 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-Ansichtscontroller aus, geben Sie ihm einen Namen (zEmployeeItem. B. in diesem Beispiel), und klicken Sie auf die Schaltfläche "Neu", um folgendes zu erstellen:>

    Hinzufügen eines neuen Ansichtscontrollers

    Dadurch wird der Projektmappe eine Datei EmployeeItemController.cs und EmployeeItemController.xib eine EmployeeItem.csDatei hinzugefügt.

  3. Doppelklicken Sie auf die EmployeeItemController.xib Datei, um sie zum Bearbeiten im Schnittstellen-Generator von Xcode zu öffnen.

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

    Entwerfen des Layouts des Zellprototyps

  5. Öffnen Sie den Assistenten-Editor , und erstellen Sie eine Steckdose , NSBox damit sie verwendet werden kann, um den Auswahlstatus einer Zelle anzugeben:

    Verfügbarmachen des NSBox-Steuerelements in einem Ausgang

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

  7. Wählen Sie im Bindungsinspektor die Option "An Dateibesitzer binden>" aus, und geben Sie einen Modellschlüsselpfad von self.Person.Icon:

    Binden des Symbols

  8. Wählen Sie die erste Bezeichnung aus, und wählen Sie im Bindungsinspektor die Option "An Dateibesitzer binden>" aus, und geben Sie einen Modellschlüsselpfad ein:self.Person.Name

    Binden des Namens

  9. Wählen Sie die zweite Bezeichnung und im Bindungsinspektor die Option "An Dateibesitzer binden>" aus, und geben Sie einen Modellschlüsselpfad ein:self.Person.Occupation

    Bindung der Tätigkeit

  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 stellen Sie sicher, dass sie wie folgt aussieht:

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 diesen Code im Detail betrachten, erbt die Klasse, NSCollectionViewItem damit sie als Prototyp für eine Sammlungsansichtszelle fungieren kann. Die Person Eigenschaft macht die Klasse verfügbar, die zum Binden an die Bildansicht und beschriftungen in Xcode verwendet wurde. Dies ist eine Instanz der PersonModel oben erstellten.

Die BackgroundColor Eigenschaft ist eine Verknüpfung mit dem NSBox Steuerelement FillColor , das verwendet wird, um den Auswahlstatus einer Zelle anzuzeigen. Durch Überschreiben der Selected Eigenschaft des NSCollectionViewItemCodes wird 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 (mithilfe des .xib Prototyps) nach Bedarf für jedes Element in der Auflistung auf.

Fügen Sie eine neue Klasse des Projekts hinzu, nennen Sie sie CollectionViewDataSource , und stellen Sie sicher, dass sie wie folgt aussieht:

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

Im Detail wird dieser Code von der Klasse geerbt NSCollectionViewDataSource und eine Liste von PersonModel Instanzen über ihre Data Eigenschaft verfügbar gemacht.

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 überschrieben, um die Anzahl der Elemente in der Data Eigenschaftsliste zurückgibt.

Die GetItem Methode wird immer aufgerufen, wenn eine neue Zelle erforderlich ist und wie folgt aussieht:

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 Instanz der EmployeeItemController Auflistungsansicht zu erstellen oder zurückzugeben, und ihre Person Eigenschaft wird auf das Element festgelegt, das in der angeforderten Zelle angezeigt wird.

Der EmployeeItemController Code muss vorab mit dem Sammlungsansichtscontroller registriert werden:

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

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

Behandeln der Elementauswahl

Zum Behandeln der Auswahl und Deselection von Elementen in der Auflistung ist eine 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 stellen Sie sicher, dass sie wie folgt aussieht:

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 ItemsDeselected werden überschrieben und zum Festlegen oder Löschen der PersonSelected Eigenschaft des Ansichtscontrollers verwendet, der die Sammlungsansicht behandelt, wenn der Benutzer ein Element auswählt oder deaktiviert. Dies wird unten im Detail angezeigt.

Erstellen der Sammlungsansicht im Schnittstellen-Generator

Da 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 auf die Main.StoryboardDatei im Projektmappen-Explorer, um sie zum Bearbeiten im Schnittstellen-Generator von Xcode zu öffnen.

  2. Ziehen Sie eine Sammlungsansicht in die Hauptansicht, und ändern Sie die 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 in der Entwurfsoberfläche ausgewählt ist (und nicht die gerahmente Bildlaufansicht oder Clip View, die sie enthält), wechseln Sie zum Assistenten-Editor, und erstellen Sie eine Steckdose für die Sammlungsansicht:

    Screenshot des Assistenten-Editors, in dem Sie eine Steckdose erstellen können.

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

Alles zusammenbringen

Alle unterstützenden Teile wurden nun mit einer Klasse platziert, die als Datenmodell (PersonModel), eine NSCollectionViewDataSource hinzugefügt wurde, um Daten zu liefern, eine NSCollectionViewDelegateFlowLayout wurde erstellt, um die Elementauswahl zu behandeln und eine 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 Sammlung aufzufüllen und die Elementauswahl zu behandeln.

Bearbeiten Sie die ViewController.cs Datei, und stellen Sie sicher, dass sie wie folgt aussieht:

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

Im Detail dieses Codes wird eine Datasource Eigenschaft definiert, um eine Instanz der CollectionViewDataSource Daten für die Sammlungsansicht bereitzustellen. Eine PersonSelected Eigenschaft wird definiert, um das PersonModel aktuell ausgewählte Element in der Sammlungsansicht darzustellen. 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 mit der folgenden Zeile fungiert:

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

Beachten Sie, dass der zum Registrieren des Prototyps verwendete BezeichnerEmployeeCell dem in der GetItem oben definierten Methode CollectionViewDataSource aufgerufenen entspricht:

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 durch eine Sammlungsansichtslayoutklasse gesteuert und kann zur Laufzeit dynamisch geändert werden, indem der CollectionViewLayout Eigenschaft eine neue Instanz zugewiesen wird. Wenn Sie diese Eigenschaft ändern, wird die Darstellung der Sammlungsansicht aktualisiert, ohne die Änderung zu animieren.

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

In diesem Beispiel wird das Standardflusslayout verwendet, sodass eine Instanz 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 minimalen Abstand zwischen Elementen und MinimumLineSpacing definiert den minimalen Abstand zwischen Zeilen in der Auflistung.

Das Layout wird der Sammlungsansicht zugewiesen und eine Instanz der CollectionViewDelegate Elementauswahl zugeordnet:

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

Die PopulateWithData Methode erstellt eine neue Instanz des Objekts 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 außer Kraft gesetzt und ruft die ConfigureCollectionView methoden auf PopulateWithData , um die endgültige Sammlungsansicht für den Benutzer anzuzeigen:

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

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

Zusammenfassung

Dieser Artikel hat einen detaillierten Blick auf die Arbeit mit Sammlungsansichten in einer Xamarin.Mac-Anwendung genommen. Zunächst wurde untersucht, wie eine C#-Klasse Objective-C mithilfe von Key-Value Coding (KVC) und Key-Value Observing (KVO) verfügbar wird. Als Nächstes wurde gezeigt, wie sie eine KVO-kompatible Klasse und datenbindung an Sammlungsansichten im Schnittstellen-Generator von Xcode verwenden. Schließlich wurde gezeigt, wie sie mit Sammlungsansichten im C#-Code interagieren.