Partager via


Listes sources dans Xamarin.Mac

Cet article traite de l’utilisation des listes sources dans une application Xamarin.Mac. Il décrit la création et la gestion des listes sources dans Xcode et Interface Builder et l’interaction avec eux dans le code C#.

Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes listes sources que celles dans Objective-C lesquelles un développeur travaille et Xcode . Étant donné que Xamarin.Mac s’intègre directement à Xcode, vous pouvez utiliser le Générateur d’interface de Xcode pour créer et gérer vos listes sources (ou éventuellement les créer directement dans le code C#).

Une liste de sources est un type spécial d’affichage hiérarchique utilisé pour afficher la source d’une action, comme la barre latérale dans Finder ou iTunes.

Exemple de liste source

Dans cet article, nous allons aborder les principes fondamentaux de l’utilisation des listes sources dans une application Xamarin.Mac. Il est fortement suggéré que vous travaillez tout d’abord dans l’article Hello, Mac , en particulier les sections Introduction to Xcode and Interface Builder et Outlets and Actions , car elle couvre les concepts et techniques clés que nous utiliserons dans cet article.

Vous pouvez également examiner les classes /méthodes C# exposantes dans Objective-Cla section du document interne Xamarin.Mac, ainsi que les Register Export instructions utilisées pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.

Présentation des listes sources

Comme indiqué ci-dessus, une liste de sources est un type spécial d’affichage hiérarchique utilisé pour afficher la source d’une action, comme la barre latérale dans Finder ou iTunes. Une liste source est un type de table qui permet à l’utilisateur de développer ou de réduire les lignes de données hiérarchiques. Contrairement à une vue table, les éléments d’une liste source ne se trouvent pas dans une liste plate, ils sont organisés dans une hiérarchie, comme les fichiers et les dossiers sur un disque dur. Si un élément d’une liste source contient d’autres éléments, il peut être développé ou réduit par l’utilisateur.

La liste source est une vue hiérarchique spécialement style (NSOutlineView), qui est elle-même une sous-classe de l’affichage table (NSTableView) et, par conséquent, hérite beaucoup de son comportement de sa classe parente. Par conséquent, de nombreuses opérations prises en charge par un mode Plan sont également prises en charge par une liste source. Une application Xamarin.Mac contrôle ces fonctionnalités et peut configurer les paramètres de la liste source (dans le code ou le Générateur d’interface) pour autoriser ou interdire certaines opérations.

Une liste de sources ne stocke pas ses propres données, au lieu de cela, elle s’appuie sur une source de données (NSOutlineViewDataSource) pour fournir les lignes et les colonnes requises, selon les besoins.

Le comportement d’une liste source peut être personnalisé en fournissant une sous-classe du délégué en mode Plan (NSOutlineViewDelegate) pour prendre en charge le type Plan pour sélectionner des fonctionnalités, la sélection et la modification d’éléments, le suivi personnalisé et les vues personnalisées pour des éléments individuels.

Étant donné qu’une liste source partage une grande partie de son comportement et de ses fonctionnalités avec une vue table et un mode Plan, vous pouvez passer par la documentation sur les vues de tableau et les vues hiérarchiques avant de continuer avec cet article.

Utilisation des listes sources

Une liste de sources est un type spécial d’affichage hiérarchique utilisé pour afficher la source d’une action, comme la barre latérale dans Finder ou iTunes. Contrairement aux vues hiérarchiques, avant de définir notre liste source dans le Générateur d’interface, nous allons créer les classes de stockage dans Xamarin.Mac.

Tout d’abord, nous allons créer une SourceListItem classe pour contenir les données de notre liste de sources. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter>un nouveau fichier... Sélectionnez Classe vide générale>, entrez SourceListItem le nom, puis cliquez sur le bouton Nouveau :

Ajout d’une classe vide

Faites en sorte que le SourceListItem.cs fichier ressemble à ce qui suit :

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

Dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter>un nouveau fichier... Sélectionnez Classe vide générale>, entrez SourceListDataSource le nom, puis cliquez sur le bouton Nouveau. Faites en sorte que le SourceListDataSource.cs fichier ressemble à ce qui suit :

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

Cela fournira les données de notre liste de sources.

Dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter>un nouveau fichier... Sélectionnez Classe vide générale>, entrez SourceListDelegate le nom, puis cliquez sur le bouton Nouveau. Faites en sorte que le SourceListDelegate.cs fichier ressemble à ce qui suit :

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

Cela fournira le comportement de notre liste source.

Enfin, dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet et sélectionnez Ajouter>un nouveau fichier... Sélectionnez Classe vide générale>, entrez SourceListView le nom, puis cliquez sur le bouton Nouveau. Faites en sorte que le SourceListView.cs fichier ressemble à ce qui suit :

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

Cela crée une sous-classe personnalisée et réutilisable de NSOutlineView (SourceListView) que nous pouvons utiliser pour piloter la liste source dans n’importe quelle application Xamarin.Mac que nous créons.

Création et maintenance de listes sources dans Xcode

Nous allons maintenant concevoir notre liste source dans le Générateur d’interface. Double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans le Générateur d’interface et faites glisser un mode Fractionné à partir de l’inspecteur de bibliothèque, ajoutez-le au contrôleur de vue et définissez-le pour le redimensionner avec l’affichage dans l’éditeur de contraintes :

Modification des contraintes dans le Générateur d’interface.

Ensuite, faites glisser une liste source à partir de l’inspecteur de bibliothèque, ajoutez-la à gauche de l’affichage fractionné et définissez-la pour la redimensionner avec l’affichage dans l’éditeur de contraintes :

Modification des contraintes en faisant glisser une liste source vers l’affichage fractionné.

Ensuite, basculez vers l’affichage d’identité, sélectionnez la liste source et remplacez la classe SourceListViewpar :

Définition du nom de la classe

Enfin, créez une sortie pour notre liste source appelée SourceList dans le ViewController.h fichier :

Configuration d’un point de sortie

Enregistrez vos modifications et revenez à Visual Studio pour Mac à synchroniser avec Xcode.

Remplissage de la liste source

Nous allons modifier le RotationWindow.cs fichier dans Visual Studio pour Mac et faire en sorte que sa AwakeFromNib méthode ressemble à ce qui suit :

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

}

La Initialize () méthode doit être appelée sur le point de sortie de notre liste source avant d’y ajouter des éléments. Pour chaque groupe d’éléments, nous créons un élément parent, puis ajoutons les sous-éléments à cet élément de groupe. Chaque groupe est ensuite ajouté à la collection SourceList.AddItem (...)source List. Les deux dernières lignes chargent les données de la liste source et développent tous les groupes :

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

Enfin, modifiez le AppDelegate.cs fichier et faites en sorte que la DidFinishLaunching méthode ressemble à ce qui suit :

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

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

Si nous exécutons notre application, les éléments suivants s’affichent :

Exemple d’exécution d’application

Résumé

Cet article a examiné en détail l’utilisation des listes sources dans une application Xamarin.Mac. Nous avons vu comment créer et gérer des listes sources dans le Générateur d’interface de Xcode et comment utiliser des listes sources dans du code C#.