Quelllisten in Xamarin.Mac

In diesem Artikel wird das Arbeiten mit Quelllisten in einer Xamarin.Mac-Anwendung behandelt. Es beschreibt das Erstellen und Verwalten von Quelllisten in Xcode und Interface Builder sowie die Interaktion mit ihnen in C#-Code.

Wenn Sie mit C# und .NET in einer Xamarin.Mac-Anwendung arbeiten, haben Sie Zugriff auf die gleichen Quelllisten wie ein Entwickler, der in Objective-C und Xcode arbeitet. Da Xamarin.Mac direkt in Xcode integriert wird, können Sie den Schnittstellen-Generator von Xcode verwenden, um Ihre Quelllisten zu erstellen und zu verwalten (oder optional direkt in C#-Code zu erstellen).

Eine Quellliste ist eine spezielle Art von Gliederungsansicht, die verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes.

Eine Beispielquellenliste

In diesem Artikel werden die Grundlagen der Arbeit mit Quelllisten in einer Xamarin.Mac-Anwendung behandelt. Es wird dringend empfohlen, dass Sie zuerst den Artikel Hello, Mac durcharbeiten, insbesondere die Abschnitte Einführung in Xcode und Interface Builder und Outlets und Aktionen , da er wichtige Konzepte und Techniken behandelt, die wir in diesem Artikel verwenden 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.

Einführung in Quelllisten

Wie bereits erwähnt, ist eine Quellliste eine spezielle Art von Gliederungsansicht, die verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes. Eine Quellliste ist ein Typ von Table, der es dem Benutzer ermöglicht, Zeilen hierarchischer Daten zu erweitern oder zu reduzieren. Im Gegensatz zu einer Tabellenansicht befinden sich Elemente in einer Quellliste nicht in einer flachen Liste, sie sind in einer Hierarchie organisiert, z. B. Dateien und Ordner auf einer Festplatte. Wenn ein Element in einer Quellliste andere Elemente enthält, kann es vom Benutzer erweitert oder reduziert werden.

Die Quellliste ist eine speziell formatierte Gliederungsansicht (NSOutlineView), die selbst eine Unterklasse der Tabellenansicht (NSTableView) ist und als solche einen Großteil ihres Verhaltens von ihrer übergeordneten Klasse erbt. Daher werden viele Vorgänge, die von einer Gliederungsansicht unterstützt werden, auch von einer Quellliste unterstützt. Eine Xamarin.Mac-Anwendung hat die Kontrolle über diese Features und kann die Parameter der Quellliste (entweder im Code oder im Schnittstellen-Generator) konfigurieren, um bestimmte Vorgänge zuzulassen oder zu verbieten.

Eine Quellliste speichert keine eigenen Daten, sondern basiert auf einer Datenquelle (NSOutlineViewDataSource), um die erforderlichen Zeilen und Spalten nach Bedarf bereitzustellen.

Das Verhalten einer Quellliste kann angepasst werden, indem eine Unterklasse des Gliederungsansichtsdelegaten (NSOutlineViewDelegate) bereitgestellt wird, um den Gliederungstyp zum Auswählen von Funktionen, Elementauswahl und -bearbeitung, benutzerdefinierter Nachverfolgung und benutzerdefinierten Ansichten für einzelne Elemente zu unterstützen.

Da eine Quellliste einen Großteil ihres Verhaltens und ihrer Funktionalität mit einer Tabellenansicht und einer Gliederungsansicht teilt, sollten Sie unsere Dokumentation zu Tabellen- undGliederungsansichten durchgehen, bevor Sie mit diesem Artikel fortfahren.

Arbeiten mit Quelllisten

Eine Quellliste ist eine spezielle Art von Gliederungsansicht, die verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes. Im Gegensatz zu Gliederungsansichten erstellen wir die Sicherungsklassen in Xamarin.Mac, bevor wir die Quellliste im Schnittstellen-Generator definieren.

Zunächst erstellen wir eine neue SourceListItem Klasse, die die Daten für unsere Quellliste enthält. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeue Dateihinzufügen>... aus. Wählen Sie Allgemein>Leere Klasse aus, geben Sie SourceListItem als Name ein, und klicken Sie auf die Schaltfläche Neu:

Hinzufügen einer leeren Klasse

Lassen Sie die SourceListItem.cs Datei wie folgt aussehen:

using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;

namespace MacOutlines
{
    public class SourceListItem: NSObject, IEnumerator, IEnumerable
    {
        #region Private Properties
        private string _title;
        private NSImage _icon;
        private string _tag;
        private List<SourceListItem> _items = new List<SourceListItem> ();
        #endregion

        #region Computed Properties
        public string Title {
            get { return _title; }
            set { _title = value; }
        }

        public NSImage Icon {
            get { return _icon; }
            set { _icon = value; }
        }

        public string Tag {
            get { return _tag; }
            set { _tag=value; }
        }
        #endregion

        #region Indexer
        public SourceListItem this[int index]
        {
            get
            {
                return _items[index];
            }

            set
            {
                _items[index] = value;
            }
        }

        public int Count {
            get { return _items.Count; }
        }

        public bool HasChildren {
            get { return (Count > 0); }
        }
        #endregion

        #region Enumerable Routines
        private int _position = -1;

        public IEnumerator GetEnumerator()
        {
            _position = -1;
            return (IEnumerator)this;
        }

        public bool MoveNext()
        {
            _position++;
            return (_position < _items.Count);
        }

        public void Reset()
        {_position = -1;}

        public object Current
        {
            get 
            { 
                try 
                {
                    return _items[_position];
                }

                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }
        #endregion

        #region Constructors
        public SourceListItem ()
        {
        }

        public SourceListItem (string title)
        {
            // Initialize
            this._title = title;
        }

        public SourceListItem (string title, string icon)
        {
            // Initialize
            this._title = title;
            this._icon = NSImage.ImageNamed (icon);
        }

        public SourceListItem (string title, string icon, ClickedDelegate clicked)
        {
            // Initialize
            this._title = title;
            this._icon = NSImage.ImageNamed (icon);
            this.Clicked = clicked;
        }

        public SourceListItem (string title, NSImage icon)
        {
            // Initialize
            this._title = title;
            this._icon = icon;
        }

        public SourceListItem (string title, NSImage icon, ClickedDelegate clicked)
        {
            // Initialize
            this._title = title;
            this._icon = icon;
            this.Clicked = clicked;
        }

        public SourceListItem (string title, NSImage icon, string tag)
        {
            // Initialize
            this._title = title;
            this._icon = icon;
            this._tag = tag;
        }

        public SourceListItem (string title, NSImage icon, string tag, ClickedDelegate clicked)
        {
            // Initialize
            this._title = title;
            this._icon = icon;
            this._tag = tag;
            this.Clicked = clicked;
        }
        #endregion

        #region Public Methods
        public void AddItem(SourceListItem item) {
            _items.Add (item);
        }

        public void AddItem(string title) {
            _items.Add (new SourceListItem (title));
        }

        public void AddItem(string title, string icon) {
            _items.Add (new SourceListItem (title, icon));
        }

        public void AddItem(string title, string icon, ClickedDelegate clicked) {
            _items.Add (new SourceListItem (title, icon, clicked));
        }

        public void AddItem(string title, NSImage icon) {
            _items.Add (new SourceListItem (title, icon));
        }

        public void AddItem(string title, NSImage icon, ClickedDelegate clicked) {
            _items.Add (new SourceListItem (title, icon, clicked));
        }

        public void AddItem(string title, NSImage icon, string tag) {
            _items.Add (new SourceListItem (title, icon, tag));
        }

        public void AddItem(string title, NSImage icon, string tag, ClickedDelegate clicked) {
            _items.Add (new SourceListItem (title, icon, tag, clicked));
        }

        public void Insert(int n, SourceListItem item) {
            _items.Insert (n, item);
        }

        public void RemoveItem(SourceListItem item) {
            _items.Remove (item);
        }

        public void RemoveItem(int n) {
            _items.RemoveAt (n);
        }

        public void Clear() {
            _items.Clear ();
        }
        #endregion

        #region Events
        public delegate void ClickedDelegate();
        public event ClickedDelegate Clicked;

        internal void RaiseClickedEvent() {
            // Inform caller
            if (this.Clicked != null)
                this.Clicked ();
        }
        #endregion
    }
}

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeue Dateihinzufügen>... aus. Wählen Sie Allgemein>Leere Klasse aus, geben Sie SourceListDataSource als Name ein, und klicken Sie auf die Schaltfläche Neu. Lassen Sie die SourceListDataSource.cs Datei wie folgt aussehen:

using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;

namespace MacOutlines
{
    public class SourceListDataSource : NSOutlineViewDataSource
    {
        #region Private Variables
        private SourceListView _controller;
        #endregion

        #region Public Variables
        public List<SourceListItem> Items = new List<SourceListItem>();
        #endregion

        #region Constructors
        public SourceListDataSource (SourceListView controller)
        {
            // Initialize
            this._controller = controller;
        }
        #endregion

        #region Override Properties
        public override nint GetChildrenCount (NSOutlineView outlineView, Foundation.NSObject item)
        {
            if (item == null) {
                return Items.Count;
            } else {
                return ((SourceListItem)item).Count;
            }
        }

        public override bool ItemExpandable (NSOutlineView outlineView, Foundation.NSObject item)
        {
            return ((SourceListItem)item).HasChildren;
        }

        public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, Foundation.NSObject item)
        {
            if (item == null) {
                return Items [(int)childIndex];
            } else {
                return ((SourceListItem)item) [(int)childIndex]; 
            }
        }

        public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
        {
            return new NSString (((SourceListItem)item).Title);
        }
        #endregion

        #region Internal Methods
        internal SourceListItem ItemForRow(int row) {
            int index = 0;

            // Look at each group
            foreach (SourceListItem item in Items) {
                // Is the row inside this group?
                if (row >= index && row <= (index + item.Count)) {
                    return item [row - index - 1];
                }

                // Move index
                index += item.Count + 1;
            }

            // Not found 
            return null;
        }
        #endregion
    }
}

Dadurch werden die Daten für unsere Quellliste bereitgestellt.

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeue Dateihinzufügen>... aus. Wählen Sie Allgemein>Leere Klasse aus, geben Sie SourceListDelegate als Name ein, und klicken Sie auf die Schaltfläche Neu. Lassen Sie die SourceListDelegate.cs Datei wie folgt aussehen:

using System;
using AppKit;
using Foundation;

namespace MacOutlines
{
    public class SourceListDelegate : NSOutlineViewDelegate
    {
        #region Private variables
        private SourceListView _controller;
        #endregion

        #region Constructors
        public SourceListDelegate (SourceListView controller)
        {
            // Initialize
            this._controller = controller;
        }
        #endregion

        #region Override Methods
        public override bool ShouldEditTableColumn (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
        {
            return false;
        }

        public override NSCell GetCell (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
        {
            nint row = outlineView.RowForItem (item);
            return tableColumn.DataCellForRow (row);
        }

        public override bool IsGroupItem (NSOutlineView outlineView, Foundation.NSObject item)
        {
            return ((SourceListItem)item).HasChildren;
        }

        public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
        {
            NSTableCellView view = null;

            // Is this a group item?
            if (((SourceListItem)item).HasChildren) {
                view = (NSTableCellView)outlineView.MakeView ("HeaderCell", this);
            } else {
                view = (NSTableCellView)outlineView.MakeView ("DataCell", this);
                view.ImageView.Image = ((SourceListItem)item).Icon;
            }

            // Initialize view
            view.TextField.StringValue = ((SourceListItem)item).Title;

            // Return new view
            return view;
        }

        public override bool ShouldSelectItem (NSOutlineView outlineView, Foundation.NSObject item)
        {
            return (outlineView.GetParent (item) != null);
        }

        public override void SelectionDidChange (NSNotification notification)
        {
            NSIndexSet selectedIndexes = _controller.SelectedRows;

            // More than one item selected?
            if (selectedIndexes.Count > 1) {
                // Not handling this case
            } else {
                // Grab the item
                var item = _controller.Data.ItemForRow ((int)selectedIndexes.FirstIndex);

                // Was an item found?
                if (item != null) {
                    // Fire the clicked event for the item
                    item.RaiseClickedEvent ();

                    // Inform caller of selection
                    _controller.RaiseItemSelected (item);
                }
            }
        }
        #endregion
    }
}

Dadurch wird das Verhalten unserer Quellliste bereitgestellt.

Klicken Sie abschließend im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeue Dateihinzufügen>... aus. Wählen Sie Allgemein>Leere Klasse aus, geben Sie SourceListView als Name ein, und klicken Sie auf die Schaltfläche Neu. Lassen Sie die SourceListView.cs Datei wie folgt aussehen:

using System;
using AppKit;
using Foundation;

namespace MacOutlines
{
    [Register("SourceListView")]
    public class SourceListView : NSOutlineView
    {
        #region Computed Properties
        public SourceListDataSource Data {
            get {return (SourceListDataSource)this.DataSource; }
        }
        #endregion

        #region Constructors
        public SourceListView ()
        {

        }

        public SourceListView (IntPtr handle) : base(handle)
        {

        }

        public SourceListView (NSCoder coder) : base(coder)
        {

        }

        public SourceListView (NSObjectFlag t) : base(t)
        {

        }
        #endregion

        #region Override Methods
        public override void AwakeFromNib ()
        {
            base.AwakeFromNib ();
        }
        #endregion

        #region Public Methods
        public void Initialize() {

            // Initialize this instance
            this.DataSource = new SourceListDataSource (this);
            this.Delegate = new SourceListDelegate (this);

        }
        
        public void AddItem(SourceListItem item) {
            if (Data != null) {
                Data.Items.Add (item);
            }
        }
        #endregion

        #region Events
        public delegate void ItemSelectedDelegate(SourceListItem item);
        public event ItemSelectedDelegate ItemSelected;

        internal void RaiseItemSelected(SourceListItem item) {
            // Inform caller
            if (this.ItemSelected != null) {
                this.ItemSelected (item);
            }
        }
        #endregion
    }
}

Dadurch wird eine benutzerdefinierte, wiederverwendbare Unterklasse von NSOutlineView (SourceListView) erstellt, die wir verwenden können, um die Quellliste in jeder von uns erstellten Xamarin.Mac-Anwendung zu steuern.

Erstellen und Verwalten von Quelllisten in Xcode

Als Nächstes entwerfen wir die Quellliste im Schnittstellen-Generator. Doppelklicken Sie auf die Main.storyboard Datei, um sie zur Bearbeitung im Schnittstellen-Generator zu öffnen, und ziehen Sie eine geteilte Ansicht aus dem Bibliotheksinspektor, fügen Sie sie dem Ansichtscontroller hinzu, und legen Sie sie so fest, dass die Größe mit der Ansicht im Einschränkungs-Editor geändert wird:

Bearbeiten von Einschränkungen im Schnittstellen-Generator.

Ziehen Sie als Nächstes eine Quellliste aus dem Bibliotheksinspektor, fügen Sie sie auf der linken Seite der geteilten Ansicht hinzu, und legen Sie sie so fest, dass die Größe mit der Ansicht im Einschränkungs-Editor geändert wird:

Bearbeiten von Einschränkungen durch Ziehen einer Quellliste in die geteilte Ansicht.

Wechseln Sie als Nächstes zur Identitätsansicht, wählen Sie die Quellliste aus, und ändern Sie die Klasse in SourceListView:

Festlegen des Klassennamens

Erstellen Sie schließlich ein Outlet für unsere Quellliste mit dem Namen SourceList in der ViewController.h Datei:

Konfigurieren einer Steckdose

Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um sie mit Xcode zu synchronisieren.

Auffüllen der Quellliste

Bearbeiten Sie die RotationWindow.cs Datei in Visual Studio für Mac und lassen Sie die AwakeFromNib -Methode wie folgt aussehen:

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

    // Populate source list
    SourceList.Initialize ();

    var library = new SourceListItem ("Library");
    library.AddItem ("Venues", "house.png", () => {
        Console.WriteLine("Venue Selected");
    });
    library.AddItem ("Singers", "group.png");
    library.AddItem ("Genre", "cards.png");
    library.AddItem ("Publishers", "box.png");
    library.AddItem ("Artist", "person.png");
    library.AddItem ("Music", "album.png");
    SourceList.AddItem (library);

    // Add Rotation 
    var rotation = new SourceListItem ("Rotation"); 
    rotation.AddItem ("View Rotation", "redo.png");
    SourceList.AddItem (rotation);

    // Add Kiosks
    var kiosks = new SourceListItem ("Kiosks");
    kiosks.AddItem ("Sign-in Station 1", "imac");
    kiosks.AddItem ("Sign-in Station 2", "ipad");
    SourceList.AddItem (kiosks);

    // Display side list
    SourceList.ReloadData ();
    SourceList.ExpandItem (null, true);

}

Die Initialize () -Methode muss für das Outlet der Quellliste aufgerufen werden, bevor Elemente hinzugefügt werden. Für jede Gruppe von Elementen erstellen wir ein übergeordnetes Element und fügen dann die Unterelemente zu diesem Gruppenelement hinzu. Jede Gruppe wird dann der Auflistung SourceList.AddItem (...)der Quellliste hinzugefügt. Die letzten beiden Zeilen laden die Daten für die Quellliste und erweitern alle Gruppen:

// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);

Bearbeiten Sie schließlich die AppDelegate.cs Datei, und lassen Sie die DidFinishLaunching Methode wie folgt aussehen:

public override void DidFinishLaunching (NSNotification notification)
{
    mainWindowController = new MainWindowController ();
    mainWindowController.Window.MakeKeyAndOrderFront (this);

    var rotation = new RotationWindowController ();
    rotation.Window.MakeKeyAndOrderFront (this);
}

Wenn wir unsere Anwendung ausführen, wird Folgendes angezeigt:

Beispiel für eine App-Ausführung

Zusammenfassung

In diesem Artikel wird das Arbeiten mit Quelllisten in einer Xamarin.Mac-Anwendung ausführlich erläutert. Wir haben erfahren, wie Sie Quelllisten im Schnittstellen-Generator von Xcode erstellen und verwalten und wie Sie mit Quelllisten in C#-Code arbeiten.