Udostępnij za pośrednictwem


Widoki kolekcji na platformie Xamarin.Mac

W tym artykule opisano pracę z widokami kolekcji w aplikacji platformy Xamarin.Mac. Obejmuje tworzenie i konserwowanie widoków kolekcji w programie Xcode i narzędziu Interface Builder oraz programowe pracę z nimi.

Podczas pracy z językiem C# i platformą .NET w aplikacji platformy Xamarin.Mac deweloper ma dostęp do tych samych kontrolek widoku kolekcji AppKit, w których pracuje Objective-C deweloper i czy program Xcode . Ponieważ platforma Xamarin.Mac integruje się bezpośrednio z programem Xcode, deweloper używa konstruktora interfejsu Xcode do tworzenia i obsługi widoków kolekcji.

Obiekt NSCollectionView wyświetla siatkę widoków podrzędnych zorganizowanych przy użyciu elementu NSCollectionViewLayout. Każdy widok podrzędny w siatce jest reprezentowany przez element NSCollectionViewItem , który zarządza ładowaniem .xib zawartości widoku z pliku.

Uruchamianie przykładowej aplikacji

W tym artykule opisano podstawy pracy z widokami kolekcji w aplikacji Xamarin.Mac. Zdecydowanie zaleca się, aby najpierw zapoznać się z artykułem Hello, Mac , w szczególności wprowadzenie do narzędzi Xcode i Interface Builder i Outlets and Actions , ponieważ obejmuje ona kluczowe pojęcia i techniki, które są używane w tym artykule.

Warto zapoznać się również z sekcją Uwidacznianie klas/ metod Objective-C języka C# w dokumencie Xamarin.Mac Internals . Register Objaśnienie poleceń i Export używanych do podłączania klas języka C# do Objective-C obiektów i elementów interfejsu użytkownika.

Informacje o widokach kolekcji

Głównym celem widoku kolekcji (NSCollectionView) jest wizualne rozmieszczenie grupy obiektów w zorganizowany sposób przy użyciu układu widoku kolekcji (), z każdym pojedynczym obiektem (NSCollectionViewLayoutNSCollectionViewItem) uzyskującym własny widok w większej kolekcji. Widoki kolekcji działają za pomocą technik tworzenia powiązań danych i kodowania klucz-wartość. W związku z tym należy zapoznać się z dokumentacją powiązania danych i kodowania klucz-wartość przed kontynuowaniem pracy z tym artykułem.

Widok kolekcji nie ma standardowego, wbudowanego elementu widoku kolekcji (takiego jak kontur lub widok tabeli), dlatego deweloper jest odpowiedzialny za projektowanie i implementowanie widoku prototypu przy użyciu innych kontrolek AppKit, takich jak Pola obrazów, Pola tekstowe, Etykiety itp. Ten widok prototypu będzie używany do wyświetlania i pracy z każdym elementem zarządzanym .xib przez widok kolekcji i jest przechowywany w pliku.

Ponieważ deweloper jest odpowiedzialny za wygląd i działanie elementu widoku kolekcji, widok kolekcji nie ma wbudowanej obsługi wyróżniania wybranego elementu w siatce. Zaimplementowanie tej funkcji zostanie omówione w tym artykule.

Definiowanie modelu danych

Przed powiązaniem danych widoku kolekcji w narzędziu Interface Builder należy zdefiniować klasę zgodną ze standardem KVC (Key-Value Observing) /Key-Value Observing (KVO) w aplikacji Xamarin.Mac, aby działać jako model danych dla powiązania. Model danych udostępnia wszystkie dane, które będą wyświetlane w kolekcji i otrzymują wszelkie modyfikacje danych, które użytkownik wprowadza w interfejsie użytkownika podczas uruchamiania aplikacji.

Przykład aplikacji, która zarządza grupą pracowników, można użyć następującej klasy do zdefiniowania modelu danych:

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

Model PersonModel danych będzie używany w pozostałej części tego artykułu.

Praca z widokiem kolekcji

Powiązanie danych z widokiem kolekcji jest bardzo podobne do powiązania z widokiem tabeli, ponieważ NSCollectionViewDataSource służy do udostępniania danych dla kolekcji. Ponieważ widok kolekcji nie ma wstępnie ustawionego formatu wyświetlania, wymagana jest większa praca w celu przekazywania opinii o interakcji użytkownika i śledzenia wyboru użytkownika.

Tworzenie prototypu komórki

Ponieważ widok kolekcji nie zawiera domyślnego prototypu komórki, deweloper będzie musiał dodać jeden lub więcej .xib plików do aplikacji Xamarin.Mac, aby zdefiniować układ i zawartość poszczególnych komórek.

Należy wykonać następujące czynności:

  1. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy nazwę projektu i wybierz polecenie Dodaj>nowy plik...

  2. Wybierz pozycję Kontroler widoku dla komputerów Mac>, nadaj mu nazwę (na EmployeeItem przykład w tym przykładzie) i kliknij przycisk Nowy, aby utworzyć:

    Dodawanie nowego kontrolera widoku

    Spowoduje to dodanie pliku EmployeeItem.csEmployeeItemController.cs i do EmployeeItemController.xib rozwiązania projektu.

  3. Kliknij dwukrotnie plik, aby otworzyć go do edycji w narzędziu EmployeeItemController.xib Xcode Interface Builder.

  4. Dodaj kontrolkę i NSImageView dwie NSLabel kontrolki NSBoxdo widoku i ułóż je w następujący sposób:

    Projektowanie układu prototypu komórki

  5. Otwórz Edytor Asystenta i utwórz gniazdo dla NSBox elementu , aby można było go użyć do wskazania stanu zaznaczenia komórki:

    Uwidacznianie NSBox w ujściu

  6. Wróć do edytora standardowego i wybierz widok obrazu.

  7. W inspektorze powiązania wybierz pozycję Powiąż z>właścicielem pliku i wprowadź ścieżkęklucza modelu :self.Person.Icon

    Wiązanie ikony

  8. Wybierz pierwszą etykietę, a następnie w inspektorze powiązań wybierz pozycję Powiąż z>właścicielem pliku i wprowadź ścieżkę klucza modelu :self.Person.Name

    Wiązanie nazwy

  9. Wybierz drugą etykietę, a następnie w inspektorze powiązań wybierz pozycję Powiąż z>właścicielem pliku i wprowadź ścieżkę klucza modelu :self.Person.Occupation

    Wiązanie zawodu

  10. Zapisz zmiany w .xib pliku i wróć do programu Visual Studio, aby zsynchronizować zmiany.

Zmodyfikuj EmployeeItemController.cs plik i utwórz go w następujący sposób:

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

Patrząc na ten kod szczegółowo, klasa dziedziczy z NSCollectionViewItem , aby mogła działać jako prototyp dla komórki Widok kolekcji. Właściwość Person uwidacznia klasę, która została użyta do powiązania danych z widokiem obrazu i etykietami w programie Xcode. Jest to wystąpienie utworzonego PersonModel powyżej.

Właściwość BackgroundColor jest skrótem do kontrolki NSBoxFillColor , która będzie używana do pokazywania stanu zaznaczenia komórki. Przesłaniając Selected właściwość NSCollectionViewItem, następujące zestawy kodu lub czyści ten stan zaznaczenia:

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

Tworzenie źródła danych widoku kolekcji

Źródło danych widoku kolekcji (NSCollectionViewDataSource) udostępnia wszystkie dane widoku kolekcji i tworzy i wypełnia komórkę widoku kolekcji (przy użyciu prototypu .xib ) zgodnie z wymaganiami dla każdego elementu w kolekcji.

Dodaj nową klasę projektu, wywołaj go CollectionViewDataSource i utwórz ją tak, jakby wyglądała następująco:

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

Patrząc na ten kod szczegółowo, klasa dziedziczy i NSCollectionViewDataSource uwidacznia listę PersonModel wystąpień za pośrednictwem jej Data właściwości.

Ponieważ ta kolekcja ma tylko jedną sekcję, kod zastępuje metodę GetNumberOfSections i zawsze zwraca wartość 1. GetNumberofItems Ponadto metoda jest zastępowana, zwraca liczbę elementów na Data liście właściwości.

Metoda jest wywoływana GetItem za każdym razem, gdy jest wymagana nowa komórka i wygląda następująco:

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

    return item;
}

MakeItem Metoda widoku kolekcji jest wywoływana w celu utworzenia lub zwrócenia wystąpienia wielokrotnego użytku obiektu EmployeeItemController , a jego Person właściwość jest ustawiona na element wyświetlany w żądanej komórce.

Element EmployeeItemController musi być wcześniej zarejestrowany w kontrolerze widoku kolekcji przy użyciu następującego kodu:

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

Identyfikator (EmployeeCell) użyty w wywołaniu MakeItemmusi być zgodny z nazwą kontrolera widoku, który został zarejestrowany w widoku kolekcji. Ten krok zostanie szczegółowo omówiony poniżej.

Obsługa zaznaczenia elementu

Aby obsłużyć zaznaczenie i usunięcie zaznaczenia elementów w kolekcji, NSCollectionViewDelegate będzie wymagane. Ponieważ w tym przykładzie będzie używany wbudowany NSCollectionViewFlowLayout typ układu, NSCollectionViewDelegateFlowLayout wymagana będzie określona wersja tego delegata.

Dodaj nową klasę do projektu, wywołaj ją CollectionViewDelegate i utwórz ją w następujący sposób:

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

Metody ItemsSelected i ItemsDeselected są zastępowane i używane do ustawiania lub czyszczenia PersonSelected właściwości kontrolera widoku, który obsługuje widok kolekcji, gdy użytkownik wybiera lub usuwa zaznaczenie elementu. Zostanie to pokazane szczegółowo poniżej.

Tworzenie widoku kolekcji w narzędziu Interface Builder

Ze wszystkimi wymaganymi elementami pomocniczymi można edytować główny scenorys i dodać do niego widok kolekcji.

Należy wykonać następujące czynności:

  1. Main.Storyboard Kliknij dwukrotnie plik w Eksplorator rozwiązań, aby otworzyć go do edycji w narzędziu Xcode Interface Builder.

  2. Przeciągnij widok kolekcji do widoku głównego i zmień jego rozmiar, aby wypełnić widok:

    Dodawanie widoku kolekcji do układu

  3. Po wybraniu widoku kolekcji użyj edytora ograniczeń, aby przypiąć go do widoku po zmianie rozmiaru:

    Zrzut ekranu przedstawiający dodawanie nowych ograniczeń.

  4. Upewnij się, że widok kolekcji jest zaznaczony na powierzchni projektowej (a nie w widoku obramowania przewijania lub wycinek, który go zawiera), przejdź do Edytora Asystenta i utwórz gniazdo dla widoku kolekcji:

    Zrzut ekranu przedstawia Edytor asystenta, w którym można utworzyć gniazdo.

  5. Zapisz zmiany i wróć do programu Visual Studio, aby przeprowadzić synchronizację.

Łączenie tego wszystkiego razem

Wszystkie elementy pomocnicze zostały teraz wprowadzone z klasą do działania jako model danych (PersonModel), dodano element do dostarczania danych, utworzono element NSCollectionViewDelegateFlowLayout do obsługi wyboru elementów i NSCollectionView element został dodany do głównego scenorysu i uwidoczniony jako gniazdo (EmployeeCollectionNSCollectionViewDataSource).

Ostatnim krokiem jest edytowanie kontrolera widoku zawierającego widok kolekcji i przeniesienie wszystkich elementów w celu wypełnienia kolekcji i obsługi zaznaczenia elementu.

Zmodyfikuj ViewController.cs plik i utwórz go w następujący sposób:

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

Przyjrzyjmy się szczegółowo temu kodowi, Datasource a właściwość jest definiowana w celu przechowywania wystąpienia CollectionViewDataSource obiektu , które będzie dostarczać dane dla widoku kolekcji. Właściwość PersonSelected jest definiowana do przechowywania PersonModel reprezentującego aktualnie wybranego elementu w widoku kolekcji. Ta właściwość zgłasza SelectionChanged również zdarzenie, gdy wybór ulegnie zmianie.

Klasa ConfigureCollectionView służy do rejestrowania kontrolera widoku, który działa jako prototyp komórki w widoku kolekcji przy użyciu następującego wiersza:

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

Zwróć uwagę, że identyfikator (EmployeeCell) użyty do zarejestrowania prototypu jest zgodny z identyfikatorem wywołanym w GetItem metodzie zdefiniowanej CollectionViewDataSource powyżej:

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

Ponadto typ kontrolera widoku musi być zgodny z nazwą .xib pliku, który dokładnie definiuje prototyp. W przypadku tego przykładu EmployeeItemController i EmployeeItemController.xib.

Rzeczywisty układ elementów w widoku kolekcji jest kontrolowany przez klasę Układ widoku kolekcji i można go dynamicznie zmieniać w czasie wykonywania, przypisując nowe wystąpienie do CollectionViewLayout właściwości . Zmiana tej właściwości powoduje zaktualizowanie wyglądu widoku kolekcji bez animowania zmiany.

Firma Apple dostarcza dwa wbudowane typy układów z widokiem kolekcji, które będą obsługiwać najbardziej typowe zastosowania: NSCollectionViewFlowLayout i NSCollectionViewGridLayout. Jeśli deweloper wymaga formatu niestandardowego, takiego jak układanie elementów w okręgu, może utworzyć niestandardowe wystąpienie NSCollectionViewLayout i zastąpić wymagane metody, aby osiągnąć pożądany efekt.

W tym przykładzie użyto domyślnego NSCollectionViewFlowLayout układu przepływu, aby utworzyć wystąpienie klasy i skonfigurować go w następujący sposób:

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

Właściwość ItemSize definiuje rozmiar każdej pojedynczej komórki w kolekcji. Właściwość SectionInset definiuje zestawy z krawędzi kolekcji, w których będą rozmieszczone komórki. MinimumInteritemSpacing definiuje minimalne odstępy między elementami i MinimumLineSpacing definiuje minimalne odstępy między wierszami w kolekcji.

Układ jest przypisywany do widoku kolekcji, a wystąpienie elementu CollectionViewDelegate jest dołączone do obsługi zaznaczenia elementu:

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

Metoda PopulateWithData tworzy nowe wystąpienie CollectionViewDataSourceobiektu , wypełnia je danymi, dołącza je do widoku kolekcji i wywołuje ReloadData metodę w celu wyświetlenia elementów:

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 jest zastępowana i wywołuje ConfigureCollectionView metody i PopulateWithData w celu wyświetlenia końcowego widoku kolekcji użytkownikowi:

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

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

Podsumowanie

W tym artykule szczegółowo przedstawiono pracę z widokami kolekcji w aplikacji platformy Xamarin.Mac. Najpierw przyjrzeliśmy się uwidacznieniu klasy Objective-C C# przy użyciu kodowania klucz-wartość (KVC) i obserwowania wartości klucz-wartość (KVO). Następnie pokazano, jak używać klasy zgodnej z KVO i powiązać je z widokami kolekcji w narzędziu Interface Builder programu Xcode. Na koniec pokazano, jak korzystać z widoków kolekcji w kodzie języka C#.