Quelllisten in Xamarin.Mac

In diesem Artikel wird die Arbeit mit Quelllisten in einer Xamarin.Mac-Anwendung behandelt. Es beschreibt das Erstellen und Standard Beibehalten von Quelllisten im Xcode- und Schnittstellen-Generator und die Interaktion mit ihnen im C#-Code.

Beim Arbeiten mit C# und .NET in einer Xamarin.Mac-Anwendung haben Sie Zugriff auf die gleichen Quelllisten, in Objective-C denen ein Entwickler arbeitet und Xcode ausführt. Da Xamarin.Mac direkt in Xcode integriert ist, können Sie den Schnittstellen-Generator von Xcode verwenden, um Ihre Quelllisten zu erstellen und zu Standard (oder optional direkt im C#-Code zu erstellen).

Eine Quellliste ist ein spezieller Typ von Gliederungsansicht, der verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes.

Beispielquellenliste

In diesem Artikel behandeln wir die Grundlagen der Arbeit mit Quelllisten in einer Xamarin.Mac-Anwendung. 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 "Actions ", da es sich um wichtige Konzepte und Techniken handelt, die wir in diesem Artikel verwenden werden.

Möglicherweise möchten Sie sich auch die Verfügbarmachen von C#-Klassen /-Methoden imObjective-CAbschnitt des Xamarin.Mac Internals-Dokuments ansehen, und es werden die befehle Export erläutert, die Register zum Verketten Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.

Einführung in Quelllisten

Wie oben erwähnt, ist eine Quellliste ein spezieller Typ von Gliederungsansicht, der verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes. Eine Quellliste ist ein Tabellentyp, der es dem Benutzer ermöglicht, Zeilen mit hierarchischen 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 angeordnet, 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), bei der es sich selbst um eine Unterklasse der Tabellenansicht (NSTableView) handelt und als solche einen Großteil ihres Verhaltens von der ü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 verfügt über 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 sowohl die erforderlichen Zeilen als auch die erforderlichen Spalten bereitzustellen.

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

Da eine Quellliste einen Großteil des Verhaltens und der Funktionalität mit einer Tabellenansicht und einer Gliederungsansicht teilt, sollten Sie die Dokumentation zu Tabellenansichten und Gliederungsansichten durchgehen, bevor Sie mit diesem Artikel fortfahren.

Arbeiten mit Quelllisten

Eine Quellliste ist ein spezieller Typ von Gliederungsansicht, der verwendet wird, um die Quelle einer Aktion anzuzeigen, z. B. die Seitenleiste in Finder oder iTunes. Im Gegensatz zu Gliederungsansichten erstellen wir vor dem Definieren unserer Quellliste im Schnittstellen-Generator die Sicherungsklassen in Xamarin.Mac.

Als Erstes erstellen wir eine neue SourceListItem Klasse, um die Daten für unsere Quellliste zu enthalten. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie "Neue Datei hinzufügen>" aus... Wählen Sie "Allgemein>leere Klasse" aus, geben Sie SourceListItemden Namen ein, und klicken Sie auf die Schaltfläche "Neu":

Hinzufügen einer leeren Klasse

Stellen Sie sicher, dass die SourceListItem.cs Datei wie folgt aussieht:

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 Sie "Neue Datei hinzufügen>" aus... Wählen Sie "Allgemein>leere Klasse" aus, geben Sie SourceListDataSource den Namen ein, und klicken Sie auf die Schaltfläche "Neu". Stellen Sie sicher, dass die SourceListDataSource.cs Datei wie folgt aussieht:

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 Sie "Neue Datei hinzufügen>" aus... Wählen Sie "Allgemein>leere Klasse" aus, geben Sie SourceListDelegate den Namen ein, und klicken Sie auf die Schaltfläche "Neu". Stellen Sie sicher, dass die SourceListDelegate.cs Datei wie folgt aussieht:

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 Sie "Neue Datei hinzufügen>" aus... Wählen Sie "Allgemein>leere Klasse" aus, geben Sie SourceListView den Namen ein, und klicken Sie auf die Schaltfläche "Neu". Stellen Sie sicher, dass die SourceListView.cs Datei wie folgt aussieht:

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 einer beliebigen Xamarin.Mac-Anwendung zu steuern, die wir erstellen.

Erstellen und Verwalten von Quelllisten in Xcode

Als Nächstes entwerfen wir unsere Quellliste im Schnittstellen-Generator. Doppelklicken Sie auf die Main.storyboard Datei, um sie zum Bearbeiten 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 sie mit der Ansicht im Einschränkungs-Editor geändert wird:

Bearbeitungseinschränkungen im Schnittstellen-Generator.

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

Bearbeitungseinschrä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, die in der ViewController.h Datei aufgerufen wirdSourceList:

Konfigurieren einer Steckdose

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

Auffüllen der Quellliste

Lassen Sie uns die RotationWindow.cs Datei in Visual Studio für Mac bearbeiten und 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 den Ausgangder 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 Sammlung 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 stellen Sie sicher, dass die DidFinishLaunching Methode wie folgt aussieht:

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

Dieser Artikel hat einen detaillierten Blick auf die Arbeit mit Quelllisten in einer Xamarin.Mac-Anwendung gemacht. Wir haben gesehen, wie Sie Quelllisten im Schnittstellen-Generator von Xcode erstellen und Standard und wie Sie mit Quelllisten im C#-Code arbeiten.