Zobrazení kolekcí v Xamarin.Mac

Tento článek popisuje práci se zobrazeními kolekcí v aplikaci Xamarin.Mac. Zabývá se vytvářením a údržbou zobrazení kolekcí v Xcode a Interface Builderu a pracuje s nimi programově.

Při práci s C# a .NET v aplikaci Xamarin.Mac má vývojář přístup ke stejným ovládacím prvkům Zobrazení kolekce AppKit, které vývojář pracuje a Objective-CXcode . Vzhledem k tomu, že Xamarin.Mac se integruje přímo s Xcode, vývojář používá Tvůrce rozhraní Xcode k vytváření a údržbě zobrazení kolekcí.

A NSCollectionView zobrazí mřížku dílčích zobrazení uspořádaných pomocí NSCollectionViewLayout. Každé dílčí zobrazení v mřížce je reprezentováno NSCollectionViewItem tím, že spravuje načítání obsahu zobrazení ze .xib souboru.

An example app run

Tento článek popisuje základy práce se zobrazeními kolekce v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste nejprve prošli článek Hello, Mac , konkrétně úvod do Xcode a Interface Builder a Outlets a Actions , protože se zabývá klíčovými koncepty a technikami, které se používají v tomto článku.

Můžete se také podívat na metody nebo třídy jazyka C#, které se zobrazí v Objective-C dokumentu Xamarin.Mac Internals , vysvětluje Register a Export příkazy používané k připojení tříd jazyka C# k Objective-C objektům a prvkům uživatelského rozhraní.

O zobrazeních kolekce

Hlavním cílem zobrazení kolekce (NSCollectionView) je vizuálně uspořádat skupinu objektů uspořádaným způsobem pomocí rozložení zobrazení kolekce (NSCollectionViewLayout), přičemž každý jednotlivý objekt (NSCollectionViewItem) získá vlastní zobrazení ve větší kolekci. Zobrazení kolekcí fungují prostřednictvím datových vazeb a technik kódování Key-Value, a proto byste si měli přečíst dokumentaci k datové vazbě a Key-Value kódování , než budete pokračovat v tomto článku.

Zobrazení kolekce nemá žádnou standardní integrovanou položku zobrazení kolekce (například osnovu nebo zobrazení tabulky), takže vývojář zodpovídá za návrh a implementaci zobrazení prototypu pomocí jiných ovládacích prvků AppKitu, jako jsou pole obrázků, textová pole, popisky atd. Toto zobrazení prototypu se použije k zobrazení a práci s každou položkou spravovanou zobrazením kolekce a bude uložena v .xib souboru.

Vzhledem k tomu, že vývojář zodpovídá za vzhled a chování položky zobrazení kolekce, nemá zobrazení kolekce žádnou integrovanou podporu pro zvýraznění vybrané položky v mřížce. Implementace této funkce bude popsána v tomto článku.

Definování datového modelu

Před vytvořením datové vazby v Tvůrci rozhraní musí být v aplikaci Xamarin.Mac definována třída kompatibilní s kódováním Key-Value (KVC)/Key-Value Observing (KVO), aby pro vazbu fungovala jako datový model . Datový model poskytuje všechna data, která se zobrazí v kolekci, a přijímá veškeré změny dat, která uživatel provede v uživatelském rozhraní při spuštění aplikace.

Příklad aplikace, která spravuje skupinu zaměstnanců, je možné použít k definování datového modelu následující třídu:

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

Datový PersonModel model se použije ve zbývající části tohoto článku.

Práce se zobrazením kolekce

Datová vazba se zobrazením kolekce je velmi podobná vazbě se zobrazením tabulky, jak NSCollectionViewDataSource se používá k poskytování dat pro kolekci. Vzhledem k tomu, že zobrazení kolekce nemá přednastavený formát zobrazení, je potřeba více práce, aby bylo možné poskytnout zpětnou vazbu k interakci uživatelů a sledovat výběr uživatelů.

Vytvoření prototypu buňky

Vzhledem k tomu, že zobrazení kolekce neobsahuje výchozí prototyp buňky, vývojář bude muset do aplikace Xamarin.Mac přidat jeden nebo více .xib souborů, aby definoval rozložení a obsah jednotlivých buněk.

Postupujte následovně:

  1. V Průzkumník řešení klikněte pravým tlačítkem na název projektu a vyberte AddNew>File...

  2. Vyberte Kontroler MacView>, pojmenujte ho (například EmployeeItem v tomto příkladu) a kliknutím na tlačítko Nový vytvořte:

    Adding a new view controller

    Tím se přidá EmployeeItem.csEmployeeItemController.cs soubor a EmployeeItemController.xib soubor do řešení projektu.

  3. Poklikáním otevřete EmployeeItemController.xib soubor pro úpravy v Tvůrci rozhraní Xcode.

  4. Přidejte do zobrazení ovládací prvky NSBoxa NSImageView dva NSLabel ovládací prvky a rozložte je následujícím způsobem:

    Designing the layout of the cell prototype

  5. Otevřete Editor pomocníka a vytvořte výstup pro NSBox buňku, aby mohl být použit k označení stavu výběru buňky:

    Exposing the NSBox in an Outlet

  6. Vraťte se do standardního editoru a vyberte zobrazení obrázku.

  7. V nástroji Binding Inspector vyberte vlastníkasouboru Bind ToFile> a zadejte cestu k klíčiself.Person.Iconmodelu:

    Binding the Icon

  8. Vyberte první popisek a v nástroji Binding Inspector vyberte vlastníkasouboru Bind ToFile> a zadejte cestu ke klíči modelu:self.Person.Name

    Binding the name

  9. Vyberte druhý popisek a v nástroji Binding Inspector vyberte vlastníkasouboru Bind ToFile> a zadejte cestu ke klíčiself.Person.Occupationmodelu:

    Binding the occupation

  10. Uložte změny do .xib souboru a vraťte se do Visual Studio, aby se změny synchronizovaly.

EmployeeItemController.cs Upravte soubor a udělejte ho takto:

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

Při podrobném pohledu na tento kód třída dědí z NSCollectionViewItem toho, aby mohl fungovat jako prototyp pro buňku Zobrazení kolekce. Vlastnost Person zveřejňuje třídu, která byla použita k vytvoření vazby na zobrazení obrázku a popisky v Xcode. Toto je instance vytvořené výše PersonModel .

Vlastnost BackgroundColor je zástupcem NSBox ovládacího prvku FillColor , který se použije k zobrazení stavu výběru buňky. Selected Přepsáním vlastnosti NSCollectionViewItem, následující kód nastaví nebo vymaže tento stav výběru:

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

Vytvoření zdroje dat zobrazení kolekce

Zdroj dat zobrazení kolekce (NSCollectionViewDataSource) poskytuje všechna data pro zobrazení kolekce a vytvoří a naplní buňku zobrazení kolekce (pomocí prototypu .xib ) podle potřeby pro každou položku v kolekci.

Přidejte novou třídu projektu, zavolejte ji CollectionViewDataSource a udělejte ji takto:

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

Při podrobném pohledu na tento kód třída dědí z NSCollectionViewDataSource a zveřejňuje seznam PersonModel instancí prostřednictvím své Data vlastnosti.

Vzhledem k tomu, že tato kolekce má pouze jednu část, kód přepíše metodu GetNumberOfSections a vždy vrátí 1. GetNumberofItems Metoda se navíc přepíše na ni vrátí počet položek v Data seznamu vlastností.

Metoda GetItem se volá při každém požadavku nové buňky a vypadá takto:

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

    return item;
}

Metoda MakeItem Zobrazení kolekce je volána k vytvoření nebo vrácení opakovaně použitelné instance objektu EmployeeItemController a jeho Person vlastnost je nastavena na položku, která se zobrazí v požadované buňce.

Musí EmployeeItemController být zaregistrována u kontroleru zobrazení kolekce předem pomocí následujícího kódu:

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

Identifikátor (EmployeeCell) použitý ve MakeItem volání musí odpovídat názvu kontroleru zobrazení, který byl zaregistrován v zobrazení kolekce. Tento krok se podrobně probírá níže.

Zpracování výběru položky

Chcete-li zpracovat výběr a zrušení výběru položek v kolekci, bude vyžadováno NSCollectionViewDelegate . Vzhledem k tomu, že tento příklad bude používat předdefinovaný NSCollectionViewFlowLayout typ rozložení, bude vyžadována NSCollectionViewDelegateFlowLayout konkrétní verze tohoto delegáta.

Přidejte do projektu novou třídu, zavolejte ji CollectionViewDelegate a udělejte ji takto:

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

Tyto ItemsSelected metody ItemsDeselected jsou přepsány a slouží k nastavení nebo vymazání PersonSelected vlastnosti kontroleru zobrazení, který zpracovává zobrazení kolekce, když uživatel vybere nebo zruší výběr položky. Zobrazí se podrobně níže.

Vytvoření zobrazení kolekce v Tvůrci rozhraní

Se všemi požadovanými podpůrnými díly je možné hlavní scénář upravit a přidat do něj zobrazení kolekce.

Postupujte následovně:

  1. Poklikejte na Main.Storyboard soubor v Průzkumník řešení a otevřete ho pro úpravy v Tvůrci rozhraní Xcode.

  2. Přetáhněte zobrazení kolekce do hlavního zobrazení a změňte jeho velikost tak, aby vyplnilo zobrazení:

    Adding a Collection View to the layout

  3. Když je vybráno zobrazení kolekce, připnutí editoru omezení na zobrazení při změně velikosti:

    Screenshot shows Add New Constraints.

  4. Ujistěte se, že je na návrhovém povrchu vybrané zobrazení kolekce (a ne zobrazení ohraničeného posuvníku nebo klipu , které ho obsahuje), přepněte do Editoru asistentů a vytvořte výstup pro zobrazení kolekce:

    Screenshot shows the Assistant Editor where you can create an Outlet.

  5. Uložte změny a vraťte se do Visual Studio pro synchronizaci.

Spojte se se všemi

Všechny podpůrné části byly nyní zavedeny s třídou, která bude fungovat jako datový model (), byla NSCollectionViewDataSource přidána k dodání dat, NSCollectionViewDelegateFlowLayout byla vytvořena pro zpracování výběru položek a NSCollectionView byla přidána do hlavní scénáře a vystavena jako výstup (EmployeeCollection).PersonModel

Posledním krokem je úprava kontroleru zobrazení, který obsahuje zobrazení kolekce, a spojení všech částí dohromady pro naplnění kolekce a zpracování výběru položek.

ViewController.cs Upravte soubor a udělejte ho takto:

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

Při podrobném pohledu na tento kód je definována Datasource vlastnost, která bude obsahovat instanci CollectionViewDataSource , která bude poskytovat data pro zobrazení kolekce. Vlastnost PersonSelected je definována pro uchování PersonModel představující aktuálně vybranou položku v zobrazení kolekce. Tato vlastnost také vyvolá SelectionChanged událost při změně výběru.

Třída ConfigureCollectionView se používá k registraci kontroleru zobrazení, který funguje jako prototyp buňky v zobrazení kolekce pomocí následujícího řádku:

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

Všimněte si, že identifikátor (EmployeeCell) použitý k registraci prototypu odpovídá identifikátoru volaného v GetItem metodě CollectionViewDataSource definované výše:

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

Kromě toho typ kontroleru zobrazení musí odpovídat názvu .xib souboru, který definuje prototyp přesně. V případě tohoto příkladu EmployeeItemController a EmployeeItemController.xib.

Skutečné rozložení položek v zobrazení kolekce je řízeno třídou Rozložení zobrazení kolekce a lze ji dynamicky změnit přiřazením nové instance vlastnosti CollectionViewLayout . Změna této vlastnosti aktualizuje vzhled zobrazení kolekce bez animace změny.

Apple dodává dva předdefinované typy rozložení s zobrazením kolekce, které budou zpracovávat nejběžnější použití: NSCollectionViewFlowLayout a NSCollectionViewGridLayout. Pokud vývojář vyžadoval vlastní formát, například rozložení položek v kruhu, může vytvořit vlastní instanci NSCollectionViewLayout a přepsat požadované metody, aby dosáhl požadovaného efektu.

Tento příklad používá výchozí rozložení toku, takže vytvoří instanci NSCollectionViewFlowLayout třídy a nakonfiguruje ji následujícím způsobem:

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

Vlastnost ItemSize definuje velikost každé jednotlivé buňky v kolekci. Vlastnost SectionInset definuje sady z okraje kolekce, ve které budou buňky rozloženy. MinimumInteritemSpacing definuje minimální mezery mezi položkami a MinimumLineSpacing definuje minimální mezery mezi řádky v kolekci.

Rozložení je přiřazeno k zobrazení kolekce a k zpracování výběru položky je připojena instance CollectionViewDelegate :

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

Metoda PopulateWithData vytvoří novou instanci CollectionViewDataSource, naplní ji daty, připojí ji k zobrazení kolekce a zavolá metodu ReloadData pro zobrazení položek:

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

Metoda ViewDidLoad se přepíše a zavolá ConfigureCollectionView metody a PopulateWithData zobrazí koncové zobrazení kolekce uživateli:

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

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

Souhrn

Tento článek se podrobně podíval na práci se zobrazeními kolekcí v aplikaci Xamarin.Mac. Nejprve se podíval na zveřejnění třídy Objective-C jazyka C# pomocí Key-Value Kódování (KVC) a Key-Value Observing (KVO). Dále ukázala, jak používat třídu kompatibilní se standardem KVO a vytvořit vazbu dat na zobrazení kolekce v Tvůrci rozhraní Xcode. Nakonec ukázal, jak pracovat se zobrazeními kolekce v kódu jazyka C#.