Sammlungsansichten in Xamarin.Mac
In diesem Artikel wird das Arbeiten mit Sammlungsansichten in einer Xamarin.Mac-App beschrieben. Es behandelt das Erstellen und Verwalten von Sammlungsansichten in Xcode und Interface Builder sowie das programmgesteuerte Arbeiten mit ihnen.
Bei der Arbeit mit C# und .NET in einer Xamarin.Mac-App hat der Entwickler Zugriff auf die gleichen AppKit-Sammlungsansichtssteuerelemente wie ein Entwickler, der in Objective-C und Xcode arbeitet. Da Xamarin.Mac direkt in Xcode integriert wird, verwendet der Entwickler den Schnittstellen-Generator von Xcode, um Sammlungsansichten zu erstellen und zu verwalten.
Ein NSCollectionView
zeigt ein Raster von Unteransichten an, die mithilfe eines NSCollectionViewLayout
organisiert sind. Jede Unteransicht im Raster wird durch eine NSCollectionViewItem
dargestellt, die das Laden des Ansichtsinhalts aus einer .xib
Datei verwaltet.
In diesem Artikel werden die Grundlagen der Arbeit mit Sammlungsansichten in einer Xamarin.Mac-App behandelt. Es wird dringend empfohlen, dass Sie zuerst den Artikel Hello, Mac durcharbeiten, insbesondere die Abschnitte Einführung in Xcode und Interface Builder sowie Outlets und Aktionen , da er die wichtigsten Konzepte und Techniken behandelt, die in diesem Artikel verwendet werden.
Möglicherweise sollten Sie auch einen Blick auf den Abschnitt Verfügbarmachen von C#-Klassen/-Methoden für Objective-C das Xamarin.Mac Internals-Dokument werfen. Darin werden die Befehle und Export
erläutert, die Register
zum Verknüpfen Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.
Informationen zu Sammlungsansichten
Das Standard Ziel einer Sammlungsansicht (NSCollectionView
) besteht darin, eine Gruppe von Objekten mithilfe eines Sammlungsansichtslayouts (NSCollectionViewLayout
) visuell organisiert anzuordnen, wobei jedes einzelne Objekt (NSCollectionViewItem
) eine eigene Ansicht in der größeren Auflistung erhält. Sammlungsansichten funktionieren über Datenbindungs- und Key-Value Codierungstechniken. Daher sollten Sie die Dokumentation zur Datenbindung und Key-Value Codierung lesen, bevor Sie mit diesem Artikel fortfahren.
Die Sammlungsansicht verfügt über kein standardmäßiges integriertes Sammlungsansichtselement (wie eine Gliederungs- oder Tabellenansicht), sodass der Entwickler für das Entwerfen und Implementieren einer Prototypansicht mit anderen AppKit-Steuerelementen wie Bildfeldern, Textfeldern, Bezeichnungen usw. verantwortlich ist. Diese Prototypansicht wird zum Anzeigen und Arbeiten mit jedem Element verwendet, das von der Sammlungsansicht verwaltet wird, und wird in einer .xib
Datei gespeichert.
Da der Entwickler für das Aussehen und Verhalten eines Sammlungsansichtselements verantwortlich ist, verfügt die Sammlungsansicht über keine integrierte Unterstützung für die Hervorhebung eines ausgewählten Elements im Raster. Die Implementierung dieses Features wird in diesem Artikel behandelt.
Definieren des Datenmodells
Vor der Datenbindung einer Sammlungsansicht im Schnittstellen-Generator muss in der Xamarin.Mac-App eine KVO-kompatible Klasse (Key-Value Coding)/Key-Value Observing (KVO) definiert werden, um als Datenmodell für die Bindung zu fungieren. Das Datenmodell stellt alle Daten bereit, die in der Sammlung angezeigt werden, und empfängt alle Änderungen an den Daten, die der Benutzer während der Ausführung der Anwendung auf der Benutzeroberfläche vornimmt.
Nehmen wir das Beispiel einer App, die eine Gruppe von Mitarbeitern verwaltet. Die folgende Klasse könnte zum Definieren des Datenmodells verwendet werden:
using System;
using Foundation;
using AppKit;
namespace MacDatabinding
{
[Register("PersonModel")]
public class PersonModel : NSObject
{
#region Private Variables
private string _name = "";
private string _occupation = "";
private bool _isManager = false;
private NSMutableArray _people = new NSMutableArray();
#endregion
#region Computed Properties
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue ("Name");
_name = value;
DidChangeValue ("Name");
}
}
[Export("Occupation")]
public string Occupation {
get { return _occupation; }
set {
WillChangeValue ("Occupation");
_occupation = value;
DidChangeValue ("Occupation");
}
}
[Export("isManager")]
public bool isManager {
get { return _isManager; }
set {
WillChangeValue ("isManager");
WillChangeValue ("Icon");
_isManager = value;
DidChangeValue ("isManager");
DidChangeValue ("Icon");
}
}
[Export("isEmployee")]
public bool isEmployee {
get { return (NumberOfEmployees == 0); }
}
[Export("Icon")]
public NSImage Icon
{
get
{
if (isManager)
{
return NSImage.ImageNamed("IconGroup");
}
else
{
return NSImage.ImageNamed("IconUser");
}
}
}
[Export("personModelArray")]
public NSArray People {
get { return _people; }
}
[Export("NumberOfEmployees")]
public nint NumberOfEmployees {
get { return (nint)_people.Count; }
}
#endregion
#region Constructors
public PersonModel ()
{
}
public PersonModel (string name, string occupation)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
}
public PersonModel (string name, string occupation, bool manager)
{
// Initialize
this.Name = name;
this.Occupation = occupation;
this.isManager = manager;
}
#endregion
#region Array Controller Methods
[Export("addObject:")]
public void AddPerson(PersonModel person) {
WillChangeValue ("personModelArray");
isManager = true;
_people.Add (person);
DidChangeValue ("personModelArray");
}
[Export("insertObject:inPersonModelArrayAtIndex:")]
public void InsertPerson(PersonModel person, nint index) {
WillChangeValue ("personModelArray");
_people.Insert (person, index);
DidChangeValue ("personModelArray");
}
[Export("removeObjectFromPersonModelArrayAtIndex:")]
public void RemovePerson(nint index) {
WillChangeValue ("personModelArray");
_people.RemoveObject (index);
DidChangeValue ("personModelArray");
}
[Export("setPersonModelArray:")]
public void SetPeople(NSMutableArray array) {
WillChangeValue ("personModelArray");
_people = array;
DidChangeValue ("personModelArray");
}
#endregion
}
}
Das PersonModel
Datenmodell wird im weiteren Verlauf dieses Artikels verwendet.
Arbeiten mit einer Sammlungsansicht
Die Datenbindung mit einer Sammlungsansicht ähnelt der Bindung mit einer Tabellenansicht, da NSCollectionViewDataSource
sie zum Bereitstellen von Daten für die Sammlung verwendet wird. Da die Sammlungsansicht kein voreingestelltes Anzeigeformat aufweist, ist mehr Arbeit erforderlich, um Feedback zu Benutzerinteraktionen bereitzustellen und die Benutzerauswahl nachzuverfolgen.
Erstellen des Zellprototyps
Da die Sammlungsansicht keinen Standardzellenprototyp enthält, muss der Entwickler der Xamarin.Mac-App eine oder .xib
mehrere Dateien hinzufügen, um das Layout und den Inhalt der einzelnen Zellen zu definieren.
Gehen Sie folgendermaßen vor:
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie Neue Datei hinzufügen>... aus.
Wählen Sie Mac>View Controller aus, geben Sie ihm einen Namen (wie
EmployeeItem
in diesem Beispiel), und klicken Sie zum Erstellen auf die Schaltfläche Neu :Dadurch werden der Projektmappe eine
EmployeeItem.cs
EmployeeItemController.cs
- undEmployeeItemController.xib
-Datei hinzugefügt.Doppelklicken Sie auf die
EmployeeItemController.xib
Datei, um sie zur Bearbeitung im Interface Builder von Xcode zu öffnen.Fügen Sie der Ansicht ein
NSBox
-NSImageView
und zweiNSLabel
-Steuerelemente hinzu, und legen Sie sie wie folgt aus:Öffnen Sie den Assistenten-Editor , und erstellen Sie ein Outlet für das
NSBox
, damit er verwendet werden kann, um den Auswahlstatus einer Zelle anzugeben:Kehren Sie zum Standard-Editor zurück , und wählen Sie die Bildansicht aus.
Wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von ein
self.Person.Icon
:Wählen Sie die erste Bezeichnung aus, und wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von ein
self.Person.Name
:Wählen Sie die zweite Bezeichnung aus, und wählen Sie im Bindungsinspektor die Option AnBesitzer der Dateibinden> aus, und geben Sie einen Modellschlüsselpfad von ein
self.Person.Occupation
:Speichern Sie die Änderungen an der
.xib
Datei, und kehren Sie zu Visual Studio zurück, um die Änderungen zu synchronisieren.
Bearbeiten Sie die EmployeeItemController.cs
Datei, und lassen Sie sie wie folgt aussehen:
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using AppKit;
namespace MacCollectionNew
{
/// <summary>
/// The Employee item controller handles the display of the individual items that will
/// be displayed in the collection view as defined in the associated .XIB file.
/// </summary>
public partial class EmployeeItemController : NSCollectionViewItem
{
#region Private Variables
/// <summary>
/// The person that will be displayed.
/// </summary>
private PersonModel _person;
#endregion
#region Computed Properties
// strongly typed view accessor
public new EmployeeItem View
{
get
{
return (EmployeeItem)base.View;
}
}
/// <summary>
/// Gets or sets the person.
/// </summary>
/// <value>The person that this item belongs to.</value>
[Export("Person")]
public PersonModel Person
{
get { return _person; }
set
{
WillChangeValue("Person");
_person = value;
DidChangeValue("Person");
}
}
/// <summary>
/// Gets or sets the color of the background for the item.
/// </summary>
/// <value>The color of the background.</value>
public NSColor BackgroundColor {
get { return Background.FillColor; }
set { Background.FillColor = value; }
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="T:MacCollectionNew.EmployeeItemController"/> is selected.
/// </summary>
/// <value><c>true</c> if selected; otherwise, <c>false</c>.</value>
/// <remarks>This also changes the background color based on the selected state
/// of the item.</remarks>
public override bool Selected
{
get
{
return base.Selected;
}
set
{
base.Selected = value;
// Set background color based on the selection state
if (value) {
BackgroundColor = NSColor.DarkGray;
} else {
BackgroundColor = NSColor.LightGray;
}
}
}
#endregion
#region Constructors
// Called when created from unmanaged code
public EmployeeItemController(IntPtr handle) : base(handle)
{
Initialize();
}
// Called when created directly from a XIB file
[Export("initWithCoder:")]
public EmployeeItemController(NSCoder coder) : base(coder)
{
Initialize();
}
// Call to load from the XIB/NIB file
public EmployeeItemController() : base("EmployeeItem", NSBundle.MainBundle)
{
Initialize();
}
// Added to support loading from XIB/NIB
public EmployeeItemController(string nibName, NSBundle nibBundle) : base(nibName, nibBundle) {
Initialize();
}
// Shared initialization code
void Initialize()
{
}
#endregion
}
}
Wenn Sie sich diesen Code im Detail ansehen, erbt die -Klasse von NSCollectionViewItem
, sodass sie als Prototyp für eine Sammlungsansichtszelle fungieren kann. Die Person
-Eigenschaft macht die -Klasse verfügbar, die zum Binden von Daten an die Bildansicht und Bezeichnungen in Xcode verwendet wurde. Dies ist eine instance der PersonModel
oben erstellten.
Die BackgroundColor
-Eigenschaft ist eine Verknüpfung zu den NSBox
SteuerelementenFillColor
, die verwendet wird, um die Auswahl status einer Zelle anzuzeigen. Durch Überschreiben der Selected
-Eigenschaft von NSCollectionViewItem
wird dieser Auswahlzustand durch den folgenden Code festgelegt oder gelöscht:
public override bool Selected
{
get
{
return base.Selected;
}
set
{
base.Selected = value;
// Set background color based on the selection state
if (value) {
BackgroundColor = NSColor.DarkGray;
} else {
BackgroundColor = NSColor.LightGray;
}
}
}
Erstellen der Datenquelle für die Sammlungsansicht
Eine Sammlungsansicht-Datenquelle (NSCollectionViewDataSource
) stellt alle Daten für eine Sammlungsansicht bereit und erstellt und füllt eine Sammlungsansichtszelle (unter Verwendung des .xib
Prototyps) nach Bedarf für jedes Element in der Auflistung.
Fügen Sie dem Projekt eine neue Klasse hinzu, rufen Sie sie CollectionViewDataSource
auf, und lassen Sie sie wie folgt aussehen:
using System;
using System.Collections.Generic;
using AppKit;
using Foundation;
namespace MacCollectionNew
{
/// <summary>
/// Collection view data source provides the data for the collection view.
/// </summary>
public class CollectionViewDataSource : NSCollectionViewDataSource
{
#region Computed Properties
/// <summary>
/// Gets or sets the parent collection view.
/// </summary>
/// <value>The parent collection view.</value>
public NSCollectionView ParentCollectionView { get; set; }
/// <summary>
/// Gets or sets the data that will be displayed in the collection.
/// </summary>
/// <value>A collection of PersonModel objects.</value>
public List<PersonModel> Data { get; set; } = new List<PersonModel>();
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:MacCollectionNew.CollectionViewDataSource"/> class.
/// </summary>
/// <param name="parent">The parent collection that this datasource will provide data for.</param>
public CollectionViewDataSource(NSCollectionView parent)
{
// Initialize
ParentCollectionView = parent;
// Attach to collection view
parent.DataSource = this;
}
#endregion
#region Override Methods
/// <summary>
/// Gets the number of sections.
/// </summary>
/// <returns>The number of sections.</returns>
/// <param name="collectionView">The parent Collection view.</param>
public override nint GetNumberOfSections(NSCollectionView collectionView)
{
// There is only one section in this view
return 1;
}
/// <summary>
/// Gets the number of items in the given section.
/// </summary>
/// <returns>The number of items.</returns>
/// <param name="collectionView">The parent Collection view.</param>
/// <param name="section">The Section number to count items for.</param>
public override nint GetNumberofItems(NSCollectionView collectionView, nint section)
{
// Return the number of items
return Data.Count;
}
/// <summary>
/// Gets the item for the give section and item index.
/// </summary>
/// <returns>The item.</returns>
/// <param name="collectionView">The parent Collection view.</param>
/// <param name="indexPath">Index path specifying the section and index.</param>
public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath)
{
var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
item.Person = Data[(int)indexPath.Item];
return item;
}
#endregion
}
}
Wenn Sie diesen Code im Detail betrachten, erbt die -Klasse von NSCollectionViewDataSource
und macht eine Liste von PersonModel
Instanzen über ihre Data
-Eigenschaft verfügbar.
Da diese Auflistung nur über einen Abschnitt verfügt, überschreibt der Code die GetNumberOfSections
-Methode und gibt immer zurück 1
. Darüber hinaus wird die GetNumberofItems
-Methode bei überschrieben, sie gibt die Anzahl der Elemente in der Data
Eigenschaftenliste zurück.
Die GetItem
-Methode wird immer dann aufgerufen, wenn eine neue Zelle erforderlich ist, und sieht wie folgt aus:
public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath)
{
var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
item.Person = Data[(int)indexPath.Item];
return item;
}
Die MakeItem
-Methode der Sammlungsansicht wird aufgerufen, um eine wiederverwendbare instance des zu erstellen oder zurückzugeben, und die EmployeeItemController
Person
-Eigenschaft wird auf das Element festgelegt, das in der angeforderten Zelle angezeigt wird.
Muss EmployeeItemController
zuvor mit dem folgenden Code beim Sammlungsansichtscontroller registriert werden:
EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");
Der im MakeItem
Aufruf verwendete Bezeichner (EmployeeCell
) muss mit dem Namen des Ansichtscontrollers übereinstimmen, der in der Sammlungsansicht registriert wurde. Dieser Schritt wird unten ausführlich behandelt.
Behandeln der Elementauswahl
Um die Auswahl und Abwahl von Elementen in der Auflistung zu behandeln, ist ein NSCollectionViewDelegate
erforderlich. Da in diesem Beispiel der integrierte NSCollectionViewFlowLayout
Layouttyp verwendet wird, ist eine NSCollectionViewDelegateFlowLayout
bestimmte Version dieses Delegaten erforderlich.
Fügen Sie dem Projekt eine neue Klasse hinzu, rufen Sie sie CollectionViewDelegate
auf, und lassen Sie sie wie folgt aussehen:
using System;
using Foundation;
using AppKit;
namespace MacCollectionNew
{
/// <summary>
/// Collection view delegate handles user interaction with the elements of the
/// collection view for the Flow-Based layout type.
/// </summary>
public class CollectionViewDelegate : NSCollectionViewDelegateFlowLayout
{
#region Computed Properties
/// <summary>
/// Gets or sets the parent view controller.
/// </summary>
/// <value>The parent view controller.</value>
public ViewController ParentViewController { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:MacCollectionNew.CollectionViewDelegate"/> class.
/// </summary>
/// <param name="parentViewController">Parent view controller.</param>
public CollectionViewDelegate(ViewController parentViewController)
{
// Initialize
ParentViewController = parentViewController;
}
#endregion
#region Override Methods
/// <summary>
/// Handles one or more items being selected.
/// </summary>
/// <param name="collectionView">The parent Collection view.</param>
/// <param name="indexPaths">The Index paths of the items being selected.</param>
public override void ItemsSelected(NSCollectionView collectionView, NSSet indexPaths)
{
// Dereference path
var paths = indexPaths.ToArray<NSIndexPath>();
var index = (int)paths[0].Item;
// Save the selected item
ParentViewController.PersonSelected = ParentViewController.Datasource.Data[index];
}
/// <summary>
/// Handles one or more items being deselected.
/// </summary>
/// <param name="collectionView">The parent Collection view.</param>
/// <param name="indexPaths">The Index paths of the items being deselected.</param>
public override void ItemsDeselected(NSCollectionView collectionView, NSSet indexPaths)
{
// Dereference path
var paths = indexPaths.ToArray<NSIndexPath>();
var index = paths[0].Item;
// Clear selection
ParentViewController.PersonSelected = null;
}
#endregion
}
}
Die ItemsSelected
Methoden und ItemsDeselected
werden überschrieben und verwendet, um die PersonSelected
Eigenschaft des Ansichtscontrollers festzulegen oder zu löschen, der die Sammlungsansicht behandelt, wenn der Benutzer ein Element auswählt oder deaktiviert. Dies wird unten im Detail gezeigt.
Erstellen der Sammlungsansicht im Schnittstellen-Generator
Wenn alle erforderlichen unterstützenden Elemente vorhanden sind, kann das Standard Storyboard bearbeitet und eine Sammlungsansicht hinzugefügt werden.
Gehen Sie folgendermaßen vor:
Doppelklicken Sie im Projektmappen-Explorer auf die
Main.Storyboard
Datei, um sie zur Bearbeitung im Xcode-Schnittstellen-Generator zu öffnen.Ziehen Sie eine Sammlungsansicht in die Hauptansicht, und ändern Sie ihre Größe, um die Ansicht auszufüllen:
Wenn die Sammlungsansicht ausgewählt ist, verwenden Sie den Einschränkungs-Editor, um sie an die Ansicht anzuheften, wenn die Größe geändert wird:
Stellen Sie sicher, dass die Sammlungsansicht auf der Entwurfsoberfläche ausgewählt ist (und nicht die umrandete Bildlaufansicht oder die Clip-Ansicht , die sie enthält), wechseln Sie zum Assistenten-Editor , und erstellen Sie einen Ausgang für die Sammlungsansicht:
Speichern Sie die Änderungen, und kehren Sie zur Synchronisierung zu Visual Studio zurück.
Alles zusammenführen
Alle unterstützenden Teile wurden nun mit einer Klasse eingerichtet, die als Datenmodell () fungiert,PersonModel
wurde hinzugefügt NSCollectionViewDataSource
, um Daten zu liefern, ein NSCollectionViewDelegateFlowLayout
wurde erstellt, um die Elementauswahl zu behandeln, und ein NSCollectionView
wurde dem Main Storyboard hinzugefügt und als Outlet (EmployeeCollection
) verfügbar gemacht.
Der letzte Schritt besteht darin, den Ansichtscontroller zu bearbeiten, der die Sammlungsansicht enthält, und alle Teile zusammenzuführen, um die Sammlungs- und Behandlungselementauswahl aufzufüllen.
Bearbeiten Sie die ViewController.cs
Datei, und lassen Sie sie wie folgt aussehen:
using System;
using AppKit;
using Foundation;
using CoreGraphics;
namespace MacCollectionNew
{
/// <summary>
/// The View controller controls the main view that houses the Collection View.
/// </summary>
public partial class ViewController : NSViewController
{
#region Private Variables
private PersonModel _personSelected;
private bool shouldEdit = true;
#endregion
#region Computed Properties
/// <summary>
/// Gets or sets the datasource that provides the data to display in the
/// Collection View.
/// </summary>
/// <value>The datasource.</value>
public CollectionViewDataSource Datasource { get; set; }
/// <summary>
/// Gets or sets the person currently selected in the collection view.
/// </summary>
/// <value>The person selected or <c>null</c> if no person is selected.</value>
[Export("PersonSelected")]
public PersonModel PersonSelected
{
get { return _personSelected; }
set
{
WillChangeValue("PersonSelected");
_personSelected = value;
DidChangeValue("PersonSelected");
RaiseSelectionChanged();
}
}
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:MacCollectionNew.ViewController"/> class.
/// </summary>
/// <param name="handle">Handle.</param>
public ViewController(IntPtr handle) : base(handle)
{
}
#endregion
#region Override Methods
/// <summary>
/// Called after the view has finished loading from the Storyboard to allow it to
/// be configured before displaying to the user.
/// </summary>
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Initialize Collection View
ConfigureCollectionView();
PopulateWithData();
}
#endregion
#region Private Methods
/// <summary>
/// Configures the collection view.
/// </summary>
private void ConfigureCollectionView()
{
EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");
// Create a flow layout
var flowLayout = new NSCollectionViewFlowLayout()
{
ItemSize = new CGSize(150, 150),
SectionInset = new NSEdgeInsets(10, 10, 10, 20),
MinimumInteritemSpacing = 10,
MinimumLineSpacing = 10
};
EmployeeCollection.WantsLayer = true;
// Setup collection view
EmployeeCollection.CollectionViewLayout = flowLayout;
EmployeeCollection.Delegate = new CollectionViewDelegate(this);
}
/// <summary>
/// Populates the Datasource with data and attaches it to the collection view.
/// </summary>
private void PopulateWithData()
{
// Make datasource
Datasource = new CollectionViewDataSource(EmployeeCollection);
// Build list of employees
Datasource.Data.Add(new PersonModel("Craig Dunn", "Documentation Manager", true));
Datasource.Data.Add(new PersonModel("Amy Burns", "Technical Writer"));
Datasource.Data.Add(new PersonModel("Joel Martinez", "Web & Infrastructure"));
Datasource.Data.Add(new PersonModel("Kevin Mullins", "Technical Writer"));
Datasource.Data.Add(new PersonModel("Mark McLemore", "Technical Writer"));
Datasource.Data.Add(new PersonModel("Tom Opgenorth", "Technical Writer"));
Datasource.Data.Add(new PersonModel("Larry O'Brien", "API Docs Manager", true));
Datasource.Data.Add(new PersonModel("Mike Norman", "API Documentor"));
// Populate collection view
EmployeeCollection.ReloadData();
}
#endregion
#region Events
/// <summary>
/// Selection changed delegate.
/// </summary>
public delegate void SelectionChangedDelegate();
/// <summary>
/// Occurs when selection changed.
/// </summary>
public event SelectionChangedDelegate SelectionChanged;
/// <summary>
/// Raises the selection changed event.
/// </summary>
internal void RaiseSelectionChanged() {
// Inform caller
if (this.SelectionChanged != null) SelectionChanged();
}
#endregion
}
}
Wenn Sie sich diesen Code im Detail ansehen, wird eine Datasource
Eigenschaft definiert, um eine instance der zu enthalten, die CollectionViewDataSource
die Daten für die Sammlungsansicht bereitstellt. Eine PersonSelected
-Eigenschaft ist definiert, um das zu enthalten, das PersonModel
das aktuell ausgewählte Element in der Sammlungsansicht darstellt. Diese Eigenschaft löst auch das SelectionChanged
-Ereignis aus, wenn sich die Auswahl ändert.
Die ConfigureCollectionView
-Klasse wird verwendet, um den Ansichtscontroller zu registrieren, der als Zellprototyp mit der Sammlungsansicht fungiert, indem die folgende Zeile verwendet wird:
EmployeeCollection.RegisterClassForItem(typeof(EmployeeItemController), "EmployeeCell");
Beachten Sie, dass der Bezeichner (EmployeeCell
), der zum Registrieren des Prototyps verwendet wird, mit dem in der GetItem
oben definierten CollectionViewDataSource
Methode aufgerufen wird:
var item = collectionView.MakeItem("EmployeeCell", indexPath) as EmployeeItemController;
...
Darüber hinaus muss der Typ des Ansichtscontrollers mit dem Namen der .xib
Datei übereinstimmen, die den Prototyp genau definiert. Im Fall dieses Beispiels EmployeeItemController
und EmployeeItemController.xib
.
Das tatsächliche Layout der Elemente in der Sammlungsansicht wird von einer Layoutklasse der Sammlungsansicht gesteuert und kann zur Laufzeit dynamisch geändert werden, indem der Eigenschaft ein neuer instance zugewiesen CollectionViewLayout
wird. Wenn Sie diese Eigenschaft ändern, wird die Darstellung der Sammlungsansicht aktualisiert, ohne die Änderung zu animieren.
Apple liefert zwei integrierte Layouttypen mit der Sammlungsansicht, die die meisten typischen Verwendungen übernimmt: NSCollectionViewFlowLayout
und NSCollectionViewGridLayout
. Wenn der Entwickler ein benutzerdefiniertes Format benötigt, z. B. das Auslegen der Elemente in einem Kreis, kann er eine benutzerdefinierte instance von NSCollectionViewLayout
erstellen und die erforderlichen Methoden überschreiben, um den gewünschten Effekt zu erzielen.
In diesem Beispiel wird das Standardflowlayout verwendet, sodass eine instance der NSCollectionViewFlowLayout
-Klasse erstellt und wie folgt konfiguriert wird:
var flowLayout = new NSCollectionViewFlowLayout()
{
ItemSize = new CGSize(150, 150),
SectionInset = new NSEdgeInsets(10, 10, 10, 20),
MinimumInteritemSpacing = 10,
MinimumLineSpacing = 10
};
Die ItemSize
-Eigenschaft definiert die Größe jeder einzelnen Zelle in der Auflistung. Die SectionInset
-Eigenschaft definiert die Einsets vom Rand der Auflistung, in der Zellen angeordnet werden. MinimumInteritemSpacing
definiert den Mindestabstand zwischen Elementen und MinimumLineSpacing
definiert den Mindestabstand zwischen Zeilen in der Auflistung.
Das Layout ist der Sammlungsansicht zugewiesen, und eine instance der ist angefügt, um die CollectionViewDelegate
Elementauswahl zu behandeln:
// Setup collection view
EmployeeCollection.CollectionViewLayout = flowLayout;
EmployeeCollection.Delegate = new CollectionViewDelegate(this);
Die PopulateWithData
-Methode erstellt eine neue instance von CollectionViewDataSource
, füllt sie mit Daten auf, fügt sie an die Sammlungsansicht an und ruft die ReloadData
-Methode auf, um die Elemente anzuzeigen:
private void PopulateWithData()
{
// Make datasource
Datasource = new CollectionViewDataSource(EmployeeCollection);
// Build list of employees
Datasource.Data.Add(new PersonModel("Craig Dunn", "Documentation Manager", true));
...
// Populate collection view
EmployeeCollection.ReloadData();
}
Die ViewDidLoad
-Methode wird überschrieben und ruft die ConfigureCollectionView
Methoden und PopulateWithData
auf, um dem Benutzer die endgültige Sammlungsansicht anzuzeigen:
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Initialize Collection View
ConfigureCollectionView();
PopulateWithData();
}
Zusammenfassung
In diesem Artikel wird die Arbeit mit Sammlungsansichten in einer Xamarin.Mac-Anwendung ausführlich erläutert. Zunächst wurde das Verfügbarmachen einer C#-Klasse Objective-C mithilfe von Key-Value Coding (KVC) und Key-Value Observing (KVO) untersucht. Als Nächstes wurde gezeigt, wie Sie eine KVO-kompatible Klasse verwenden und sie an Sammlungsansichten im Xcode-Schnittstellen-Generator binden. Schließlich wurde gezeigt, wie Sie mit Sammlungsansichten in C#-Code interagieren.