Xamarin.ios의 컬렉션 뷰Collection Views in Xamarin.Mac

이 문서에서는 Xamarin.ios 앱에서 컬렉션 뷰를 사용 하는 방법을 설명 합니다. Xcode 및 Interface Builder에서 컬렉션 뷰를 만들고 유지 관리 하 고 프로그래밍 방식으로 작업 하는 방법을 다룹니다.This article describes working with collection views in a Xamarin.Mac app. It covers creating and maintaining collection views in Xcode and Interface Builder and working with them programmatically.

Xamarin.ios 앱에서 C# 및 .net을 사용할 때 개발자는 목표-CXcode 에서 작업 하는 개발자가 동일한 appkit 컬렉션 뷰 컨트롤에 액세스할 수 있습니다.When working with C# and .NET in a Xamarin.Mac app, the developer has access to the same AppKit Collection View controls that a developer working in Objective-C and Xcode does. Xamarin.ios는 Xcode와 직접 통합 되므로 개발자는 Xcode의 Interface Builder 을 사용 하 여 컬렉션 뷰를 만들고 유지 관리 합니다.Because Xamarin.Mac integrates directly with Xcode, the developer uses Xcode's Interface Builder to create and maintain Collection Views.

NSCollectionView NSCollectionViewLayout를 사용 하 여 구성 된 하위 뷰 표를 표시 합니다.A NSCollectionView displays a grid of subviews organized using a NSCollectionViewLayout. 표의 각 하위 뷰는 .xib 파일에서 뷰의 콘텐츠 로드를 관리 하는 NSCollectionViewItem으로 표시 됩니다.Each subview in the grid is represented by a NSCollectionViewItem which manages the loading of the view’s content from a .xib file.

예제 앱 실행An example app run

이 문서에서는 Xamarin.ios 앱에서 컬렉션 보기를 사용 하는 기본 사항을 설명 합니다.This article covers the basics of working with Collection Views in a Xamarin.Mac app. 사용 되는 주요 개념 및 기술에 대해 설명 하는 대로 Hello, Mac 문서를 먼저 소개 하 고 특히 Xcode 및 Interface Builder콘센트 및 작업 섹션을 소개 하는 것이 좋습니다. 이 문서 전체.It is highly suggested that you work through the Hello, Mac article first, specifically the Introduction to Xcode and Interface Builder and Outlets and Actions sections, as it covers key concepts and techniques that are used throughout this article.

Xamarin.ios 내부 문서의 목적에 따라 클래스/메서드 노출 C# 섹션을 살펴볼 수 있습니다. 여기에서는 C# 클래스를 목표에 연결 하는 데 사용 되는RegisterExport명령을 설명 합니다. 개체 및 UI 요소You may want to take a look at the Exposing C# classes / methods to Objective-C section of the Xamarin.Mac Internals document as well, it explains the Register and Export commands used to wire-up your C# classes to Objective-C objects and UI Elements.

컬렉션 뷰 정보About Collection Views

컬렉션 뷰 (NSCollectionView)의 주요 목표는 컬렉션 뷰 레이아웃 (NSCollectionViewLayout)을 사용 하 여 구성 된 방식으로 개체 그룹을 시각적으로 정렬 하는 것입니다. 각 개별 개체 (NSCollectionViewItem)는 더 큰 컬렉션에서 자체 뷰를 가져옵니다.The main goal of a Collection View (NSCollectionView) is to visually arrange a group of objects in an organized fashion using a Collection View Layout (NSCollectionViewLayout), with each individual object (NSCollectionViewItem) getting its own View in the larger collection. 컬렉션 뷰는 데이터 바인딩 및 키-값 코딩 기술을 통해 작동 하며,이 문서를 계속 하기 전에 데이터 바인딩 및 키-값 코딩 문서를 읽어야 합니다.Collection Views work via Data Binding and Key-Value Coding techniques and as such, you should read the Data Binding and Key-Value Coding documentation before continuing with this article.

컬렉션 뷰에는 개요 나 테이블 뷰와 같은 표준 기본 제공 컬렉션 뷰 항목이 없으므로 개발자는 이미지 필드, 텍스트 필드, 레이블 등의 다른 AppKit 컨트롤을 사용 하 여 프로토타입 보기 를 디자인 하 고 구현할 책임이 있습니다. 등. 이 프로토타입 보기는 컬렉션 뷰에서 관리 되는 각 항목을 표시 하 고 작업 하는 데 사용 되며 .xib 파일에 저장 됩니다.The Collection View has no standard, built-in Collection View Item (like an Outline or Table View does), so the developer is responsible for designing and implementing a Prototype View using other AppKit controls such as Image Fields, Text Fields, Labels, etc. This Prototype View will be used to display and work with each item being managed by the Collection View and is stored in a .xib file.

개발자는 컬렉션 뷰 항목의 모양과 느낌을 담당 하므로 컬렉션 뷰에는 표에서 선택한 항목을 강조 표시 하는 기능이 기본적으로 제공 되지 않습니다.Because the developer is responsible for the look and feel of a Collection View Item, the Collection View has no built-in support for highlighting a selected item in the grid. 이 기능을 구현 하는 방법에 대해서는이 문서에서 설명 합니다.Implementing this feature will be covered in this article.

데이터 모델 정의Defining the Data Model

Interface Builder에서 컬렉션 뷰 데이터를 바인딩하기 전에 KVO (키-값 코딩) (KVC)/Key-Value 관찰 () 규격 클래스를 Xamarin.ios 앱에서 정의 하 여 바인딩에 대 한 데이터 모델 역할을 수행 해야 합니다.Before Data Binding a Collection View in Interface Builder, a Key-Value Coding (KVC)/Key-Value Observing (KVO) compliant class must be defined in the Xamarin.Mac app to act as the Data Model for the binding. 데이터 모델은 컬렉션에 표시 되는 모든 데이터를 제공 하 고 사용자가 응용 프로그램을 실행 하는 동안 UI에서 수행 하는 데이터에 대 한 모든 수정 사항을 받습니다.The Data Model provides all of the data that will be displayed in the collection and receives any modifications to the data that the user makes in the UI while running the application.

직원 그룹을 관리 하는 앱의 예를 들어 다음 클래스를 사용 하 여 데이터 모델을 정의할 수 있습니다.Take the example of an app that manages a group of employees, the following class could be used to define the Data Model:

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

PersonModel 데이터 모델은이 문서의 나머지 부분에서 사용 됩니다.The PersonModel Data Model will be used throughout the rest of this article.

컬렉션 뷰 작업Working with a Collection View

컬렉션 뷰를 사용 하는 데이터 바인딩은 컬렉션에 대 한 데이터를 제공 하는 데 NSCollectionViewDataSource를 사용 하기 때문에 테이블 뷰로 바인딩하는 것과 매우 비슷합니다.Data Binding with a Collection View is very much like binding with a Table View, as NSCollectionViewDataSource is used to provide data for the collection. 컬렉션 뷰에는 미리 설정 된 표시 형식이 없으므로 사용자 상호 작용 피드백을 제공 하 고 사용자 선택을 추적 하려면 더 많은 작업이 필요 합니다.Since the collection view doesn't have a preset display format, more work is required to provide user interaction feedback and to track user selection.

셀 프로토타입 만들기Creating the Cell Prototype

컬렉션 뷰에는 기본 셀 프로토타입이 포함 되지 않기 때문에 개발자는 Xamarin.ios 앱에 하나 이상의 .xib 파일을 추가 하 여 개별 셀의 레이아웃과 콘텐츠를 정의 해야 합니다.Since the Collection View does not include a default cell prototype, the developer will need to add one or more .xib files to the Xamarin.Mac app to define the layout and content of the individual cells.

다음을 수행합니다.Do the following:

  1. 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭 하 고 추가 > 새 파일 ...을 선택 합니다.In the Solution Explorer, right-click on the project name and select Add > New File...

  2. Mac > 보기 컨트롤러를 선택 하 고 이름을 지정 하 고 (예:이 예에서는 EmployeeItem) 새로 만들기 단추를 클릭 하 여 만듭니다.Select Mac > View Controller, give it a name (such as EmployeeItem in this example) and click the New button to create:

    새 뷰 컨트롤러 추가

    그러면 EmployeeItem.cs, EmployeeItemController.csEmployeeItemController.xib 파일이 프로젝트의 솔루션에 추가 됩니다.This will add an EmployeeItem.cs, EmployeeItemController.cs and EmployeeItemController.xib file to the project's solution.

  3. EmployeeItemController.xib 파일을 두 번 클릭 하 여 Xcode의 Interface Builder에서 편집할 수 있도록 엽니다.Double-click the EmployeeItemController.xib file to open it for editing in Xcode's Interface Builder.

  4. 뷰에 NSBox, NSImageView 및 두 개의 NSLabel 컨트롤을 추가 하 고 다음과 같이 레이아웃 합니다.Add an NSBox, NSImageView and two NSLabel controls to the View and lay them out as follows:

    셀 프로토타입의 레이아웃 디자인

  5. 길잡이 편집기 를 열고 NSBox콘센트 를 만들어 셀의 선택 상태를 나타내는 데 사용할 수 있도록 합니다.Open the Assistant Editor and create an Outlet for the NSBox so that it can be used to indicate the selection state of a cell:

    콘센트에서 NSBox 노출

  6. 표준 편집기 로 돌아가서 이미지 뷰를 선택 합니다.Return to the Standard Editor and select the Image View.

  7. 바인딩 검사자에서 > 파일의 소유자 에 바인딩 을 선택 하 고 self.Person.Icon모델 키 경로 를 입력 합니다.In the Binding Inspector, select Bind To > File's Owner and enter a Model Key Path of self.Person.Icon:

    아이콘 바인딩

  8. 첫 번째 레이블을 선택 하 고 바인딩 검사기에서 바인딩 선택 하 > 파일의 소유자 를 선택 하 고 self.Person.Name모델 키 경로 를 입력 합니다.Select the first Label and in the Binding Inspector, select Bind To > File's Owner and enter a Model Key Path of self.Person.Name:

    이름 바인딩

  9. 두 번째 레이블을 선택 하 고 바인딩 검사기에서 바인딩 선택 하 > 파일의 소유자 를 선택 하 고 self.Person.Occupation모델 키 경로 를 입력 합니다.Select the second Label and in the Binding Inspector, select Bind To > File's Owner and enter a Model Key Path of self.Person.Occupation:

    직업 바인딩

  10. .xib 파일의 변경 내용을 저장 하 고 Visual Studio로 돌아가서 변경 내용을 동기화 합니다.Save the changes to the .xib file and return to Visual Studio to sync the changes.

EmployeeItemController.cs 파일을 편집 하 여 다음과 같이 만듭니다.Edit the EmployeeItemController.cs file and make it look like the following:

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

이 코드를 자세히 살펴보면 클래스가 컬렉션 뷰 셀에 대 한 프로토타입으로 작동할 수 있도록 NSCollectionViewItem에서 상속 됩니다.Looking at this code in detail, the class inherits from NSCollectionViewItem so it can act as a prototype for a Collection View cell. Person 속성은 Xcode의 이미지 뷰 및 레이블에 데이터 바인딩하는 데 사용 된 클래스를 노출 합니다.The Person property exposes the class that was used to data bind to the Image View and Labels in Xcode. 위에서 만든 PersonModel 인스턴스입니다.This is an instance of the PersonModel created above.

BackgroundColor 속성은 셀의 선택 상태를 표시 하는 데 사용 되는 NSBox 컨트롤의 FillColor에 대 한 바로 가기입니다.The BackgroundColor property is a shortcut to the NSBox control's FillColor that will be used to show the selection status of a cell. 다음 코드는 NSCollectionViewItemSelected 속성을 재정의 하 여이 선택 상태를 설정 하거나 해제 합니다.By overriding the Selected property of the NSCollectionViewItem, the following code sets or clears this selection state:

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

컬렉션 뷰 데이터 원본 만들기Creating the Collection View Data Source

컬렉션 뷰 데이터 원본 (NSCollectionViewDataSource)은 컬렉션 뷰에 대 한 모든 데이터를 제공 하 고 컬렉션의 각 항목에 대해 필요한 만큼 컬렉션 뷰 셀 (.xib 프로토타입 사용)을 만들고 채웁니다.A Collection View Data Source (NSCollectionViewDataSource) provides all of the data for a Collection View and creates and populates a Collection View Cell (using the .xib prototype) as required for each item in the collection.

프로젝트에 새 클래스를 추가 하 고 CollectionViewDataSource 호출 하 고 다음과 같이 표시 합니다.Add a new class the project, call it CollectionViewDataSource and make it look like the following:

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

이 코드를 자세히 살펴보면 클래스가 NSCollectionViewDataSource에서 상속 하 고 Data 속성을 통해 PersonModel 인스턴스 목록을 노출 합니다.Looking at this code in detail, the class inherits from NSCollectionViewDataSource and exposes a List of PersonModel instances through its Data property.

이 컬렉션에는 하나의 섹션만 있으므로 코드는 GetNumberOfSections 메서드를 재정의 하 고 1를 항상 반환 합니다.Since this collection only has one section, the code overrides the GetNumberOfSections method and always returns 1. 또한 GetNumberofItems 메서드는 Data 속성 목록의 항목 수를 반환 합니다.Additionally, the GetNumberofItems method is overridden at it returns the number of items in the Data property list.

GetItem 메서드는 새 셀이 필요할 때마다 호출 되며 다음과 같습니다.The GetItem method is called whenever a new cell is required and looks like the following:

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 메서드는 다시 사용할 수 있는 EmployeeItemController 인스턴스를 만들거나 반환 하기 위해 호출 되 고 해당 Person 속성은 요청 된 셀에 표시 되는 항목으로 설정 됩니다.The MakeItem method of the Collection View is called to create or return a reusable instance of the EmployeeItemController and its Person property is set to item being displayed in the requested cell.

EmployeeItemController는 다음 코드를 사용 하 여 미리 컬렉션 뷰 컨트롤러에 등록 해야 합니다.The EmployeeItemController must be registered with the Collection View Controller beforehand using the following code:

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

MakeItem 호출에 사용 되는 식별자 (EmployeeCell)는 컬렉션 뷰에 등록 된 뷰 컨트롤러의 이름과 일치 해야 합니다 .The Identifier (EmployeeCell) used in the MakeItem call must match the name of the View Controller that was registered with the Collection View. 이 단계는 아래에서 자세히 설명 합니다.This step will be covered in detail below.

항목 선택 처리Handling Item Selection

컬렉션에서 항목의 선택 및 deselection을 처리 하려면 NSCollectionViewDelegate 필요 합니다.To handle the selection and deselection of items in the collection, a NSCollectionViewDelegate will be required. 이 예제에서는 기본 제공 NSCollectionViewFlowLayout 레이아웃 형식을 사용 하므로이 대리자의 NSCollectionViewDelegateFlowLayout 특정 버전이 필요 합니다.Since this example will be using the built in NSCollectionViewFlowLayout layout type, a NSCollectionViewDelegateFlowLayout specific version of this delegate will be required.

프로젝트에 새 클래스를 추가 하 고 CollectionViewDelegate 호출 하 고 다음과 같이 표시 합니다.Add a new class to the project, call it CollectionViewDelegate and make it look like the following:

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

ItemsSelectedItemsDeselected 메서드는 재정의 되 고 사용자가 항목을 선택 하거나 선택 취소할 때 컬렉션 뷰를 처리 하는 뷰 컨트롤러의 PersonSelected 속성을 설정 하거나 해제 하는 데 사용 됩니다.The ItemsSelected and ItemsDeselected methods are overridden and used to set or clear the PersonSelected property of the View Controller that is handling the Collection View when the user selects or deselects an item. 이 내용은 아래에 자세히 나와 있습니다.This will be shown in detail below.

Interface Builder에서 컬렉션 뷰 만들기Creating the Collection View in Interface Builder

필요한 모든 지원 조각이 준비 되 면 주 storyboard를 편집 하 고 여기에 컬렉션 뷰를 추가할 수 있습니다.With all of the required supporting pieces in place, the main storyboard can be edited and a Collection View added to it.

다음을 수행합니다.Do the following:

  1. 솔루션 탐색기 에서 Main.Storyboard 파일을 두 번 클릭 하 여 Xcode의 Interface Builder에서 편집할 수 있도록 엽니다.Double-click the Main.Storyboard file in the Solution Explorer to open it for editing in Xcode's Interface Builder.

  2. 컬렉션 뷰를 기본 뷰로 끌고 크기를 조정 하 여 보기를 채웁니다.Drag a Collection View into the Main View and resize it to fill the View:

    레이아웃에 컬렉션 뷰 추가

  3. 컬렉션 뷰가 선택 된 상태에서 제약 조건 편집기를 사용 하 여 크기를 조정할 때 뷰에 고정 합니다.With the Collection View selected, use the Constraint Editor to pin it to the View when it is resized:

    제약 조건 추가

  4. Design Surface 에서 컬렉션 뷰가 선택 되어 있는지 확인 하 고 (이를 포함 하는 테두리가 있는 스크롤 뷰나 클립 보기가 아닌) 도우미 편집기 로 전환 하 고 컬렉션 뷰에 대 한 콘센트 를 만듭니다.Ensure that the Collection View is selected in the Design Surface (and not the Bordered Scroll View or Clip View that contains it), switch to the Assistant Editor and create an Outlet for the collection view:

    제약 조건 추가

  5. 변경 내용을 저장 하 고 동기화를 위해 Visual Studio로 돌아갑니다.Save the changes and return to Visual Studio to sync.

모두 함께 가져오기Bringing it all Together

이제 지원 되는 모든 부분이 데이터 모델 (PersonModel)의 역할을 하는 클래스와 함께 배치 되었고, 데이터를 제공 하기 위해 NSCollectionViewDataSource 추가 되었고, 항목 선택을 처리 하기 위한 NSCollectionViewDelegateFlowLayout 생성 되었으며 주 스토리 보드에 NSCollectionView 추가 되었습니다. 콘센트 (EmployeeCollection)로 노출 됩니다.All of the supporting pieces have now been put into place with a class to act as the data model (PersonModel), a NSCollectionViewDataSource has been added to supply data, a NSCollectionViewDelegateFlowLayout was created to handle item selection and a NSCollectionView was added to the Main Storyboard and exposed as an Outlet (EmployeeCollection).

마지막 단계는 컬렉션 뷰를 포함 하는 뷰 컨트롤러를 편집 하 고 모든 조각을 함께 가져와 컬렉션을 채우고 항목 선택을 처리 하는 것입니다.The final step is to edit the View Controller that contains the Collection View and bring all of the pieces together to populate the collection and handle item selection.

ViewController.cs 파일을 편집 하 여 다음과 같이 만듭니다.Edit the ViewController.cs file and make it look like the following:

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

이 코드를 자세히 살펴보면 컬렉션 뷰에 대 한 데이터를 제공 하는 CollectionViewDataSource 인스턴스를 포함 하도록 Datasource 속성이 정의 됩니다.Taking a look at this code in detail, a Datasource property is defined to hold an instance of the CollectionViewDataSource that will provide the data for the Collection View. PersonSelected 속성은 컬렉션 뷰에서 현재 선택 된 항목을 나타내는 PersonModel를 포함 하도록 정의 됩니다.A PersonSelected property is defined to hold the PersonModel representing the currently selected item in the Collection View. 이 속성은 선택이 변경 될 때에도 SelectionChanged 이벤트를 발생 시킵니다.This property also raises the SelectionChanged event when the selection changes.

ConfigureCollectionView 클래스는 다음 줄을 사용 하 여 컬렉션 뷰를 사용 하 여 셀 프로토타입의 역할을 하는 뷰 컨트롤러를 등록 하는 데 사용 됩니다.The ConfigureCollectionView class is used to register the View Controller that acts as the cell prototype with the Collection View using the following line:

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

프로토타입을 등록 하는 데 사용 되는 식별자 (EmployeeCell)는 위에 정의 된 CollectionViewDataSourceGetItem 메서드에서 호출 된 식별자 와 일치 합니다.Notice that the Identifier (EmployeeCell) used to register the prototype matches the one called in the GetItem method of the CollectionViewDataSource defined above:

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

또한 뷰 컨트롤러의 형식은 프로토타입을 정확 하 게정의 하는 .xib 파일의 이름과 일치 해야 합니다.Additionally, the type of the View Controller must match the name of the .xib file that defines the prototype exactly. 이 예제의 경우 EmployeeItemController 하 고 EmployeeItemController.xib합니다.In the case of this example, EmployeeItemController and EmployeeItemController.xib.

컬렉션 뷰에서 항목의 실제 레이아웃은 컬렉션 뷰 레이아웃 클래스에 의해 제어 되며, CollectionViewLayout 속성에 새 인스턴스를 할당 하 여 런타임에 동적으로 변경할 수 있습니다.The actual layout of the items in the Collection View is controlled by a Collection View Layout class and can be changed dynamically at runtime by assigning a new instance to the CollectionViewLayout property. 이 속성을 변경 하면 변경 내용에 애니메이션을 적용 하지 않고 컬렉션 뷰 모양이 업데이트 됩니다.Changing this property updates the Collection View appearance without animating the change.

Apple은 가장 일반적인 용도를 처리 하는 두 가지 기본 제공 레이아웃 유형인 NSCollectionViewFlowLayoutNSCollectionViewGridLayout를 제공 합니다.Apple ships two built-in layout types with the Collection View that will handle most typical uses: NSCollectionViewFlowLayout and NSCollectionViewGridLayout. 원 안에 항목을 배치 하는 것과 같이 개발자에 게 사용자 지정 형식이 필요한 경우 NSCollectionViewLayout의 사용자 지정 인스턴스를 만들고 필요한 메서드를 재정의 하 여 원하는 효과를 달성할 수 있습니다.If the developer required a custom format, such as laying the items out in a circle, they can create a custom instance of NSCollectionViewLayout and override the required methods to achieve the desired effect.

이 예제에서는 기본 흐름 레이아웃을 사용 하 여 NSCollectionViewFlowLayout 클래스의 인스턴스를 만들고 다음과 같이 구성 합니다.This example uses the default flow layout so it creates an instance of the NSCollectionViewFlowLayout class and configures it as follows:

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

ItemSize 속성은 컬렉션에 있는 각 개별 셀의 크기를 정의 합니다.The ItemSize property defines the size of each individual cell in the collection. SectionInset 속성은 셀이 배치 될 컬렉션의 가장자리에서의 인세트를 정의 합니다.The SectionInset property defines the insets from the edge of the collection that cells will be laid out in. MinimumInteritemSpacing는 항목 사이의 최소 간격을 정의 하 고 MinimumLineSpacing는 컬렉션의 줄 사이의 최소 간격을 정의 합니다.MinimumInteritemSpacing defines the minimum spacing between items and MinimumLineSpacing defines the minimum spacing between lines in the collection.

레이아웃은 컬렉션 뷰에 할당 되 고 CollectionViewDelegate의 인스턴스는 항목 선택 항목을 처리 하는 데 연결 됩니다.The layout is assigned to the Collection View and an instance of the CollectionViewDelegate is attached to handle item selection:

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

PopulateWithData 메서드는 CollectionViewDataSource의 새 인스턴스를 만들어 데이터로 채운 다음 컬렉션 뷰에 연결 하 고 ReloadData 메서드를 호출 하 여 항목을 표시 합니다.The PopulateWithData method creates a new instance of the CollectionViewDataSource, populates it with data, attaches it to the Collection View and calls the ReloadData method to display the items:

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

ViewDidLoad 메서드는 재정의 되 고 ConfigureCollectionViewPopulateWithData 메서드를 호출 하 여 최종 컬렉션 뷰를 사용자에 게 표시 합니다.The ViewDidLoad method is overridden and calls the ConfigureCollectionView and PopulateWithData methods to display the final Collection View to the user:

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

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

요약Summary

이 문서에서는 Xamarin.ios 응용 프로그램에서 컬렉션 뷰를 사용 하는 방법을 자세히 살펴봅니다.This article has taken a detailed look at working with Collection Views in a Xamarin.Mac application. 먼저 KVC (키-값 C# 코딩) 및 키-값 관찰 (KVO)을 사용 하 여 클래스를 목표 C로 노출 하는 방법을 살펴보았습니다.First, it looked at exposing a C# class to Objective-C by using Key-Value Coding (KVC) and Key-Value Observing (KVO). 다음으로 KVO 규격 클래스를 사용 하 고 데이터를 Xcode의 Interface Builder 컬렉션 뷰에 바인딩하는 방법을 살펴보았습니다.Next, it showed how to use a KVO compliant class and Data Bind it to Collection Views in Xcode's Interface Builder. 마지막으로, 코드에서 C# 컬렉션 뷰와 상호 작용 하는 방법을 살펴보았습니다.Finally, it showed how to interact with Collection Views in C# code.