Vues de table dans Xamarin.Mac

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

Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes vues de table qu’un développeur travaillant dans Objective-C 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 vues de table (ou éventuellement les créer directement dans le code C#).

Une vue de tableau affiche des données dans un format tabulaire contenant une ou plusieurs colonnes d’informations dans plusieurs lignes. En fonction du type de vue table en cours de création, l’utilisateur peut trier par colonne, réorganiser des colonnes, ajouter des colonnes, supprimer des colonnes ou modifier les données contenues dans la table.

Exemple de tableau

Dans cet article, nous allons aborder les principes de base de l’utilisation des vues de table 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 dansObjective-Cla section du document interne Xamarin.Mac, ainsi que les RegisterExport instructions utilisées pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.

Présentation des vues de table

Une vue de tableau affiche des données dans un format tabulaire contenant une ou plusieurs colonnes d’informations dans plusieurs lignes. Les vues de tableau s’affichent à l’intérieur des vues de défilement (NSScrollView) et à partir de macOS 10.7, vous pouvez utiliser n’importe quelle NSView cellule (NSCell) pour afficher à la fois les lignes et les colonnes. Cela dit, vous pouvez toujours utiliser NSCell toutefois, vous allez généralement sous-classer NSTableCellView et créer vos lignes et colonnes personnalisées.

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

Le comportement d’une vue de table peut être personnalisé en fournissant une sous-classe du délégué d’affichage de table (NSTableViewDelegate) pour prendre en charge la gestion des colonnes de table, le type pour sélectionner les fonctionnalités, la sélection de lignes et la modification, le suivi personnalisé et les vues personnalisées pour les colonnes et lignes individuelles.

Lors de la création de vues de table, Apple suggère les éléments suivants :

  • Autoriser l’utilisateur à trier la table en cliquant sur un en-têtes de colonne.
  • Créez des en-têtes de colonne qui sont des noms ou des expressions abrégées qui décrivent les données affichées dans cette colonne.

Pour plus d’informations, consultez la section Affichages de contenu des instructions relatives à l’interface humaine OS X d’Apple.

Création et maintenance des vues de table dans Xcode

Lorsque vous créez une application Xamarin.Mac Cocoa, vous obtenez une fenêtre vide standard par défaut. Cette fenêtre est définie dans un .storyboard fichier automatiquement inclus dans le projet. Pour modifier votre conception windows, dans le Explorateur de solutions, double-cliquez sur le Main.storyboard fichier :

Sélection du storyboard principal

Cela ouvre la conception de fenêtre dans le Générateur d’interface de Xcode :

Modification de l’interface utilisateur dans Xcode

Tapez table dans la zone de recherche de l’inspecteur de bibliothèque pour faciliter la recherche des contrôles Table View :

Sélection d’une vue table dans la bibliothèque

Faites glisser une vue de tableau sur le contrôleur de vue dans l’éditeur d’interface, remplissez la zone de contenu du contrôleur de vue et définissez-la sur l’emplacement où elle se réduit et augmente avec la fenêtre de l’éditeur de contrainte :

Contraintes d’édition

Sélectionnez l’affichage table dans la hiérarchie d’interface et les propriétés suivantes sont disponibles dans l’inspecteur d’attribut :

Capture d’écran montrant les propriétés disponibles dans l’inspecteur d’attribut.

  • Mode contenu : vous permet d’utiliser des vues (NSView) ou des cellules (NSCell) pour afficher les données dans les lignes et les colonnes. À compter de macOS 10.7, vous devez utiliser les vues.
  • Floats Group Rows - If true, l’affichage Tableau dessine les cellules groupées comme s’ils sont flottants.
  • Colonnes : définit le nombre de colonnes affichées.
  • En-têtes - Si true, les colonnes auront des en-têtes.
  • Réorganisation : sitrue, l’utilisateur peut faire glisser les colonnes dans la table.
  • Redimensionnement : si true, l’utilisateur pourra faire glisser les en-têtes de colonne pour redimensionner les colonnes.
  • Dimensionnement des colonnes : contrôle la façon dont la table dimensionne automatiquement les colonnes.
  • Mise en surbrillance : contrôle le type de mise en surbrillance du tableau lorsqu’une cellule est sélectionnée.
  • Autres lignes : si true, jamais une autre ligne aura une couleur d’arrière-plan différente.
  • Grille horizontale : sélectionne le type de bordure dessinée entre les cellules horizontalement.
  • Grille verticale : sélectionne le type de bordure dessinée entre les cellules verticalement.
  • Couleur de grille : définit la couleur de bordure de cellule.
  • Arrière-plan : définit la couleur d’arrière-plan de la cellule.
  • Sélection : vous permet de contrôler la façon dont l’utilisateur peut sélectionner des cellules dans le tableau comme suit :
    • Multiple - Si true, l’utilisateur peut sélectionner plusieurs lignes et colonnes.
    • Colonne : si truel’utilisateur peut sélectionner des colonnes.
    • Tapez Select - If true, l’utilisateur peut taper un caractère pour sélectionner une ligne.
    • Vide : si truel’utilisateur n’est pas tenu de sélectionner une ligne ou une colonne, la table n’autorise aucune sélection du tout.
  • Enregistrement automatique : nom sous lequel le format des tables est automatiquement enregistré.
  • Informations sur les colonnes : si true, l’ordre et la largeur des colonnes sont automatiquement enregistrés.
  • Sauts de ligne : sélectionnez la façon dont la cellule gère les sauts de ligne.
  • Tronque la dernière ligne visible - Si true, la cellule sera tronquée dans les données ne peut pas s’adapter à ses limites.

Important

Sauf si vous conservez une application Xamarin.Mac héritée, NSView les vues de table basées doivent être utilisées sur NSCell les vues de table basées. NSCell est considéré comme hérité et peut ne pas être pris en charge à l’avenir.

Sélectionnez une colonne de table dans la hiérarchie d’interface et les propriétés suivantes sont disponibles dans l’inspecteur d’attribut :

Capture d’écran montrant les propriétés disponibles pour une colonne de table dans l’inspecteur d’attribut.

  • Titre : définit le titre de la colonne.
  • Alignement : définissez l’alignement du texte dans les cellules.
  • Police de titre : sélectionne la police du texte d’en-tête de la cellule.
  • Clé de tri : clé utilisée pour trier les données dans la colonne. Laissez vide si l’utilisateur ne peut pas trier cette colonne.
  • Sélecteur : action utilisée pour effectuer le tri. Laissez vide si l’utilisateur ne peut pas trier cette colonne.
  • Ordre : ordre de tri pour les données des colonnes.
  • Redimensionnement : sélectionne le type de redimensionnement de la colonne.
  • Modifiable : sitrue, l’utilisateur peut modifier des cellules dans un tableau basé sur des cellules.
  • Masqué : si true, la colonne est masquée.

Vous pouvez également redimensionner la colonne en faisant glisser sa poignée (centrée verticalement sur le côté droit) gauche ou droite.

Nous allons sélectionner chaque colonne dans notre affichage table et donner à la première colonne un titre et Product le deuxième Details.

Sélectionnez une vue de cellule de tableau (NSTableViewCell) dans la hiérarchie d’interface et les propriétés suivantes sont disponibles dans l’inspecteur d’attribut :

Capture d’écran montrant les propriétés disponibles pour une vue de cellule de tableau dans l’inspecteur d’attribut.

Il s’agit de toutes les propriétés d’une vue standard. Vous avez également la possibilité de redimensionner les lignes de cette colonne ici.

Sélectionnez une cellule Table View (par défaut, il s’agit d’un NSTextField) dans la hiérarchie d’interface et les propriétés suivantes sont disponibles dans l’inspecteur d’attribut :

Capture d’écran montrant les propriétés disponibles pour une cellule Table View dans l’inspecteur d’attribut.

Vous aurez toutes les propriétés d’un champ de texte standard à définir ici. Par défaut, un champ de texte standard est utilisé pour afficher les données d’une cellule d’une colonne.

Sélectionnez une vue de cellule de tableau (NSTableFieldCell) dans la hiérarchie d’interface et les propriétés suivantes sont disponibles dans l’inspecteur d’attribut :

Capture d’écran montrant les propriétés disponibles pour une autre cellule d’affichage de table dans l’inspecteur d’attribut.

Les paramètres les plus importants ici sont les suivants :

  • Disposition : sélectionnez la façon dont les cellules de cette colonne sont disposées.
  • Utilise le mode ligne unique : si true, la cellule est limitée à une seule ligne.
  • Première largeur de disposition du runtime - Si true, la cellule préfère la largeur définie pour elle (manuellement ou automatiquement) lorsqu’elle est affichée la première fois que l’application est exécutée.
  • Action : contrôle le moment où l’action d’édition est envoyée pour la cellule.
  • Comportement : définit si une cellule est sélectionnable ou modifiable.
  • Texte enrichi - Si true, la cellule peut afficher du texte mis en forme et mis en forme.
  • Annuler - Si true, la cellule assume la responsabilité de son comportement d’annulation.

Sélectionnez l’affichage de cellule de tableau (NSTableFieldCell) en bas d’une colonne de tableau dans la hiérarchie d’interface :

Sélection de l’affichage des cellules de tableau

Cela vous permet de modifier l’affichage de cellule de tableau utilisé comme modèle de base pour toutes les cellules créées pour la colonne donnée.

Ajout d’actions et de points de sortie

Tout comme n’importe quel autre contrôle d’interface utilisateur Cocoa, nous devons exposer notre vue table et ses colonnes et cellules au code C# à l’aide d’actions et de sorties (en fonction des fonctionnalités requises).

Le processus est le même pour n’importe quel élément Table View que nous voulons exposer :

  1. Basculez vers l’Éditeur Assistant et vérifiez que le ViewController.h fichier est sélectionné :

    Éditeur Assistant

  2. Sélectionnez l’affichage table dans la hiérarchie d’interface, cliquez sur le contrôle et faites glisser vers le ViewController.h fichier.

  3. Créez un point de sortie pour la vue table appelée ProductTable:

    Capture d’écran montrant une connexion de sortie créée pour l’affichage table nommé ProductTable.

  4. Créez des points de sortie pour les colonnes de tables également appelées ProductColumn et DetailsColumn:

    Capture d’écran montrant les connexions de sortie créées pour d’autres vues de table.

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

Ensuite, nous allons écrire le code pour afficher des données pour la table lors de l’exécution de l’application.

Remplissage de la vue Table

Avec notre vue de table conçue dans le Générateur d’interface et exposée via une sortie, nous devons ensuite créer le code C# pour le remplir.

Tout d’abord, nous allons créer une Product classe pour contenir les informations des lignes individuelles. 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 Product le nom, puis cliquez sur le bouton Nouveau :

Création d’une classe vide

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

using System;

namespace MacTables
{
  public class Product
  {
    #region Computed Properties
    public string Title { get; set;} = "";
    public string Description { get; set;} = "";
    #endregion

    #region Constructors
    public Product ()
    {
    }

    public Product (string title, string description)
    {
      this.Title = title;
      this.Description = description;
    }
    #endregion
  }
}

Ensuite, nous devons créer une sous-classe permettant de NSTableDataSource fournir les données de notre table à mesure qu’elle est demandée. 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 ProductTableDataSource le nom, puis cliquez sur le bouton Nouveau.

Modifiez le ProductTableDataSource.cs fichier et faites-le ressembler à ce qui suit :

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

namespace MacTables
{
  public class ProductTableDataSource : NSTableViewDataSource
  {
    #region Public Variables
    public List<Product> Products = new List<Product>();
    #endregion

    #region Constructors
    public ProductTableDataSource ()
    {
    }
    #endregion

    #region Override Methods
    public override nint GetRowCount (NSTableView tableView)
    {
      return Products.Count;
    }
    #endregion
  }
}

Cette classe dispose d’un stockage pour les éléments de notre vue table et remplace le GetRowCount nombre de lignes dans la table.

Enfin, nous devons créer une sous-classe permettant de NSTableDelegate fournir le comportement de notre table. 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 ProductTableDelegate le nom, puis cliquez sur le bouton Nouveau.

Modifiez le ProductTableDelegate.cs fichier et faites-le ressembler à ce qui suit :

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

namespace MacTables
{
  public class ProductTableDelegate: NSTableViewDelegate
  {
    #region Constants
    private const string CellIdentifier = "ProdCell";
    #endregion

    #region Private Variables
    private ProductTableDataSource DataSource;
    #endregion

    #region Constructors
    public ProductTableDelegate (ProductTableDataSource datasource)
    {
      this.DataSource = datasource;
    }
    #endregion

    #region Override Methods
    public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
    {
      // This pattern allows you reuse existing views when they are no-longer in use.
      // If the returned view is null, you instance up a new view
      // If a non-null view is returned, you modify it enough to reflect the new data
      NSTextField view = (NSTextField)tableView.MakeView (CellIdentifier, this);
      if (view == null) {
        view = new NSTextField ();
        view.Identifier = CellIdentifier;
        view.BackgroundColor = NSColor.Clear;
        view.Bordered = false;
        view.Selectable = false;
        view.Editable = false;
      }

      // Setup view based on the column selected
      switch (tableColumn.Title) {
      case "Product":
        view.StringValue = DataSource.Products [(int)row].Title;
        break;
      case "Details":
        view.StringValue = DataSource.Products [(int)row].Description;
        break;
      }

      return view;
    }
    #endregion
  }
}

Lorsque nous créons une instance du ProductTableDelegate, nous transmettons également une instance de la ProductTableDataSource table qui fournit les données de la table. La GetViewForItem méthode est responsable du renvoi d’une vue (données) pour afficher la cellule d’une colonne et d’une ligne donner. Si possible, une vue existante sera réutilisée pour afficher la cellule, sinon une nouvelle vue doit être créée.

Pour remplir la table, nous allons modifier le ViewController.cs fichier et faire en sorte que la AwakeFromNib méthode ressemble à ce qui suit :

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

  // Create the Product Table Data Source and populate it
  var DataSource = new ProductTableDataSource ();
  DataSource.Products.Add (new Product ("Xamarin.iOS", "Allows you to develop native iOS Applications in C#"));
  DataSource.Products.Add (new Product ("Xamarin.Android", "Allows you to develop native Android Applications in C#"));
  DataSource.Products.Add (new Product ("Xamarin.Mac", "Allows you to develop Mac native Applications in C#"));

  // Populate the Product Table
  ProductTable.DataSource = DataSource;
  ProductTable.Delegate = new ProductTableDelegate (DataSource);
}

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

Capture d’écran montrant une fenêtre nommée Table de produits avec trois entrées.

Tri par colonne

Permettez à l’utilisateur de trier les données dans la table en cliquant sur un en-tête de colonne. Tout d’abord, double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans le Générateur d’interface. Sélectionnez la Product colonne, entrez Title la clé de tri, compare: pour le sélecteur et sélectionnez Ascending l’ordre :

Capture d’écran montrant le Générateur d’interface dans lequel vous pouvez définir la clé de tri pour la colonne Product.

Sélectionnez la Details colonne, entrez Description la clé de tri, compare: pour le sélecteur et sélectionnez Ascending l’ordre :

Capture d’écran montrant le Générateur d’interface dans lequel vous pouvez définir la clé de tri pour la colonne Détails.

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

Nous allons maintenant modifier le ProductTableDataSource.cs fichier et ajouter les méthodes suivantes :

public void Sort(string key, bool ascending) {

  // Take action based on key
  switch (key) {
  case "Title":
    if (ascending) {
      Products.Sort ((x, y) => x.Title.CompareTo (y.Title));
    } else {
      Products.Sort ((x, y) => -1 * x.Title.CompareTo (y.Title));
    }
    break;
  case "Description":
    if (ascending) {
      Products.Sort ((x, y) => x.Description.CompareTo (y.Description));
    } else {
      Products.Sort ((x, y) => -1 * x.Description.CompareTo (y.Description));
    }
    break;
  }

}

public override void SortDescriptorsChanged (NSTableView tableView, NSSortDescriptor[] oldDescriptors)
{
  // Sort the data
  if (oldDescriptors.Length > 0) {
    // Update sort
    Sort (oldDescriptors [0].Key, oldDescriptors [0].Ascending);
  } else {
    // Grab current descriptors and update sort
    NSSortDescriptor[] tbSort = tableView.SortDescriptors;
    Sort (tbSort[0].Key, tbSort[0].Ascending);
  }

  // Refresh table
  tableView.ReloadData ();
}

La Sort méthode nous permet de trier les données dans la source de données en fonction d’un champ de classe donné Product dans l’ordre croissant ou décroissant. La méthode substituée SortDescriptorsChanged est appelée chaque fois que l’utilisation clique sur un en-tête de colonne. Il est passé la valeur clé que nous définissons dans le Générateur d’interface et l’ordre de tri de cette colonne.

Si nous exécutons l’application et cliquez dans les en-têtes de colonne, les lignes seront triées par cette colonne :

Exemple d’exécution d’application

Sélection de lignes

Si vous souhaitez autoriser l’utilisateur à sélectionner une seule ligne, double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans Interface Builder. Sélectionnez l’affichage de table dans la hiérarchie d’interface et annulez case activée la zone de case activée multiple dans l’inspecteur d’attribut :

Capture d’écran montrant le Générateur d’interface dans lequel vous pouvez sélectionner Multiple dans l’inspecteur d’attributs.

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

Ensuite, modifiez le ProductTableDelegate.cs fichier et ajoutez la méthode suivante :

public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
  return true;
}

Cela permet à l’utilisateur de sélectionner n’importe quelle ligne unique dans l’affichage table. Retournez false pour toute ShouldSelectRow ligne que vous ne souhaitez pas que l’utilisateur puisse sélectionner ou false pour chaque ligne si vous ne souhaitez pas que l’utilisateur puisse sélectionner des lignes.

La vue table (NSTableView) contient les méthodes suivantes pour l’utilisation de la sélection de lignes :

  • DeselectRow(nint) - Désélectionne la ligne donnée dans le tableau.
  • SelectRow(nint,bool) - Sélectionne la ligne donnée. Passez false le deuxième paramètre pour sélectionner une seule ligne à la fois.
  • SelectedRow - Retourne la ligne active sélectionnée dans le tableau.
  • IsRowSelected(nint) - Retourne true si la ligne donnée est sélectionnée.

Sélection de plusieurs lignes

Si vous souhaitez autoriser l’utilisateur à sélectionner plusieurs lignes, double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans Interface Builder. Sélectionnez l’affichage de table dans la hiérarchie d’interface et case activée la zone de case activée multiple dans l’inspecteur d’attribut :

Capture d’écran montrant le Générateur d’interface dans lequel vous pouvez sélectionner Plusieurs pour autoriser la sélection de plusieurs lignes.

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

Ensuite, modifiez le ProductTableDelegate.cs fichier et ajoutez la méthode suivante :

public override bool ShouldSelectRow (NSTableView tableView, nint row)
{
  return true;
}

Cela permet à l’utilisateur de sélectionner n’importe quelle ligne unique dans l’affichage table. Retournez false pour toute ShouldSelectRow ligne que vous ne souhaitez pas que l’utilisateur puisse sélectionner ou false pour chaque ligne si vous ne souhaitez pas que l’utilisateur puisse sélectionner des lignes.

La vue table (NSTableView) contient les méthodes suivantes pour l’utilisation de la sélection de lignes :

  • DeselectAll(NSObject) - Désélectionne toutes les lignes du tableau. Utilisez this le premier paramètre à envoyer dans l’objet effectuant la sélection.
  • DeselectRow(nint) - Désélectionne la ligne donnée dans le tableau.
  • SelectAll(NSobject) - Sélectionne toutes les lignes du tableau. Utilisez this le premier paramètre à envoyer dans l’objet effectuant la sélection.
  • SelectRow(nint,bool) - Sélectionne la ligne donnée. false Passez le deuxième paramètre pour effacer la sélection et sélectionnez une seule ligne, passez true pour étendre la sélection et incluez cette ligne.
  • SelectRows(NSIndexSet,bool) - Sélectionne l’ensemble de lignes donné. false Passez le deuxième paramètre pour effacer la sélection et sélectionnez uniquement une ligne, passez true pour étendre la sélection et incluez ces lignes.
  • SelectedRow - Retourne la ligne active sélectionnée dans le tableau.
  • SelectedRows - Retourne un NSIndexSet contenant les index des lignes sélectionnées.
  • SelectedRowCount - Retourne le nombre de lignes sélectionnées.
  • IsRowSelected(nint) - Retourne true si la ligne donnée est sélectionnée.

Tapez pour sélectionner une ligne

Si vous souhaitez permettre à l’utilisateur de taper un caractère avec l’affichage table sélectionné et de sélectionner la première ligne contenant ce caractère, double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans le Générateur d’interface. Sélectionnez l’affichage table dans la hiérarchie d’interface et case activée la zone Sélectionner case activée dans l’inspecteur d’attributs :

Définition du type de sélection

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

Nous allons maintenant modifier le ProductTableDelegate.cs fichier et ajouter la méthode suivante :

public override nint GetNextTypeSelectMatch (NSTableView tableView, nint startRow, nint endRow, string searchString)
{
  nint row = 0;
  foreach(Product product in DataSource.Products) {
    if (product.Title.Contains(searchString)) return row;

    // Increment row counter
    ++row;
  }

  // If not found select the first row
  return 0;
}

La GetNextTypeSelectMatch méthode prend la valeur donnée searchString et retourne la ligne du premier Product qui a cette chaîne dans elle est Title.

Si nous exécutons l’application et tapez un caractère, une ligne est sélectionnée :

Capture d’écran montrant le résultat de l’exécution de l’application.

Réorganiser les colonnes

Si vous souhaitez autoriser l’utilisateur à faire glisser des colonnes de réorganisation dans l’affichage table, double-cliquez sur le Main.storyboard fichier pour l’ouvrir pour modification dans le Générateur d’interface. Sélectionnez l’affichage table dans la hiérarchie d’interface et case activée la case activée box de réorganisation dans l’inspecteur d’attributs :

Capture d’écran montrant le Générateur d’interface dans lequel vous pouvez sélectionner Reodering dans l’inspecteur d’attributs.

Si nous accordons une valeur à la propriété Enregistrement automatique et case activée le champ Informations sur la colonne, toutes les modifications apportées à la disposition de la table seront automatiquement enregistrées pour nous et restaurées la prochaine fois que l’application est exécutée.

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

Nous allons maintenant modifier le ProductTableDelegate.cs fichier et ajouter la méthode suivante :

public override bool ShouldReorder (NSTableView tableView, nint columnIndex, nint newColumnIndex)
{
  return true;
}

La ShouldReorder méthode doit retourner true pour n’importe quelle colonne qu’elle souhaite autoriser à faire glisser à nouveau dans le newColumnIndexretour , sinon ;false

Si nous exécutons l’application, nous pouvons faire glisser les en-têtes de colonne autour pour réorganiser nos colonnes :

Exemple de colonnes réorganisées

Modification des cellules

Si vous souhaitez autoriser l’utilisateur à modifier les valeurs d’une cellule donnée, modifiez le ProductTableDelegate.cs fichier et modifiez la GetViewForItem méthode comme suit :

public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{
  // This pattern allows you reuse existing views when they are no-longer in use.
  // If the returned view is null, you instance up a new view
  // If a non-null view is returned, you modify it enough to reflect the new data
  NSTextField view = (NSTextField)tableView.MakeView (tableColumn.Title, this);
  if (view == null) {
    view = new NSTextField ();
    view.Identifier = tableColumn.Title;
    view.BackgroundColor = NSColor.Clear;
    view.Bordered = false;
    view.Selectable = false;
    view.Editable = true;

    view.EditingEnded += (sender, e) => {

      // Take action based on type
      switch(view.Identifier) {
      case "Product":
        DataSource.Products [(int)view.Tag].Title = view.StringValue;
        break;
      case "Details":
        DataSource.Products [(int)view.Tag].Description = view.StringValue;
        break;
      }
    };
  }

  // Tag view
  view.Tag = row;

  // Setup view based on the column selected
  switch (tableColumn.Title) {
  case "Product":
    view.StringValue = DataSource.Products [(int)row].Title;
    break;
  case "Details":
    view.StringValue = DataSource.Products [(int)row].Description;
    break;
  }

  return view;
}

Maintenant, si nous exécutons l’application, l’utilisateur peut modifier les cellules dans l’affichage Tableau :

Exemple de modification d’une cellule

Utilisation d’images dans les vues de tableau

Pour inclure une image dans le cadre de la cellule d’un NSTableView, vous devez modifier la façon dont les données sont retournées par la méthode de NSTableViewDelegate'sGetViewForItem la vue table pour utiliser une NSTableCellView valeur plutôt que la méthode classique NSTextField. Par exemple :

public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{

  // This pattern allows you reuse existing views when they are no-longer in use.
  // If the returned view is null, you instance up a new view
  // If a non-null view is returned, you modify it enough to reflect the new data
  NSTableCellView view = (NSTableCellView)tableView.MakeView (tableColumn.Title, this);
  if (view == null) {
    view = new NSTableCellView ();
    if (tableColumn.Title == "Product") {
      view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
      view.AddSubview (view.ImageView);
      view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
    } else {
      view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
    }
    view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
    view.AddSubview (view.TextField);
    view.Identifier = tableColumn.Title;
    view.TextField.BackgroundColor = NSColor.Clear;
    view.TextField.Bordered = false;
    view.TextField.Selectable = false;
    view.TextField.Editable = true;

    view.TextField.EditingEnded += (sender, e) => {

      // Take action based on type
      switch(view.Identifier) {
      case "Product":
        DataSource.Products [(int)view.TextField.Tag].Title = view.TextField.StringValue;
        break;
      case "Details":
        DataSource.Products [(int)view.TextField.Tag].Description = view.TextField.StringValue;
        break;
      }
    };
  }

  // Tag view
  view.TextField.Tag = row;

  // Setup view based on the column selected
  switch (tableColumn.Title) {
  case "Product":
    view.ImageView.Image = NSImage.ImageNamed ("tags.png");
    view.TextField.StringValue = DataSource.Products [(int)row].Title;
    break;
  case "Details":
    view.TextField.StringValue = DataSource.Products [(int)row].Description;
    break;
  }

  return view;
}

Pour plus d’informations, consultez la section Using Images with Table Views de notre documentation Working with Image .

Ajout d’un bouton Supprimer à une ligne

En fonction des exigences de votre application, il se peut que vous deviez fournir un bouton d’action pour chaque ligne du tableau. Par exemple, nous allons développer l’exemple d’affichage de table créé ci-dessus pour inclure un bouton Supprimer sur chaque ligne.

Tout d’abord, modifiez le Main.storyboard Générateur d’interface de Xcode, sélectionnez l’affichage table et augmentez le nombre de colonnes à trois (3). Ensuite, remplacez le titre de la nouvelle colonne par Action:

Modification du nom de la colonne

Enregistrez les modifications dans le Storyboard et revenez à Visual Studio pour Mac pour synchroniser les modifications.

Ensuite, modifiez le ViewController.cs fichier et ajoutez la méthode publique suivante :

public void ReloadTable ()
{
  ProductTable.ReloadData ();
}

Dans le même fichier, modifiez la création du délégué de vue table à l’intérieur de ViewDidLoad la méthode comme suit :

// Populate the Product Table
ProductTable.DataSource = DataSource;
ProductTable.Delegate = new ProductTableDelegate (this, DataSource);

À présent, modifiez le ProductTableDelegate.cs fichier pour inclure une connexion privée au contrôleur de vue et prendre le contrôleur en tant que paramètre lors de la création d’une nouvelle instance du délégué :

#region Private Variables
private ProductTableDataSource DataSource;
private ViewController Controller;
#endregion

#region Constructors
public ProductTableDelegate (ViewController controller, ProductTableDataSource datasource)
{
  this.Controller = controller;
  this.DataSource = datasource;
}
#endregion

Ensuite, ajoutez la nouvelle méthode privée suivante à la classe :

private void ConfigureTextField (NSTableCellView view, nint row)
{
  // Add to view
  view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
  view.AddSubview (view.TextField);

  // Configure
  view.TextField.BackgroundColor = NSColor.Clear;
  view.TextField.Bordered = false;
  view.TextField.Selectable = false;
  view.TextField.Editable = true;

  // Wireup events
  view.TextField.EditingEnded += (sender, e) => {

    // Take action based on type
    switch (view.Identifier) {
    case "Product":
      DataSource.Products [(int)view.TextField.Tag].Title = view.TextField.StringValue;
      break;
    case "Details":
      DataSource.Products [(int)view.TextField.Tag].Description = view.TextField.StringValue;
      break;
    }
  };

  // Tag view
  view.TextField.Tag = row;
}

Cela prend toutes les configurations d’affichage de texte qui étaient précédemment effectuées dans la GetViewForItem méthode et les place dans un emplacement unique et pouvant être appelé (étant donné que la dernière colonne de la table n’inclut pas une vue de texte, mais un bouton).

Enfin, modifiez la méthode et faites-la GetViewForItem ressembler à ce qui suit :

public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{

  // This pattern allows you reuse existing views when they are no-longer in use.
  // If the returned view is null, you instance up a new view
  // If a non-null view is returned, you modify it enough to reflect the new data
  NSTableCellView view = (NSTableCellView)tableView.MakeView (tableColumn.Title, this);
  if (view == null) {
    view = new NSTableCellView ();

    // Configure the view
    view.Identifier = tableColumn.Title;

    // Take action based on title
    switch (tableColumn.Title) {
    case "Product":
      view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
      view.AddSubview (view.ImageView);
      view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
      ConfigureTextField (view, row);
      break;
    case "Details":
      view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
      ConfigureTextField (view, row);
      break;
    case "Action":
      // Create new button
      var button = new NSButton (new CGRect (0, 0, 81, 16));
      button.SetButtonType (NSButtonType.MomentaryPushIn);
      button.Title = "Delete";
      button.Tag = row;

      // Wireup events
      button.Activated += (sender, e) => {
        // Get button and product
        var btn = sender as NSButton;
        var product = DataSource.Products [(int)btn.Tag];

        // Configure alert
        var alert = new NSAlert () {
          AlertStyle = NSAlertStyle.Informational,
          InformativeText = $"Are you sure you want to delete {product.Title}? This operation cannot be undone.",
          MessageText = $"Delete {product.Title}?",
        };
        alert.AddButton ("Cancel");
        alert.AddButton ("Delete");
        alert.BeginSheetForResponse (Controller.View.Window, (result) => {
          // Should we delete the requested row?
          if (result == 1001) {
            // Remove the given row from the dataset
            DataSource.Products.RemoveAt((int)btn.Tag);
            Controller.ReloadTable ();
          }
        });
      };

      // Add to view
      view.AddSubview (button);
      break;
    }

  }

  // Setup view based on the column selected
  switch (tableColumn.Title) {
  case "Product":
    view.ImageView.Image = NSImage.ImageNamed ("tag.png");
    view.TextField.StringValue = DataSource.Products [(int)row].Title;
    view.TextField.Tag = row;
    break;
  case "Details":
    view.TextField.StringValue = DataSource.Products [(int)row].Description;
    view.TextField.Tag = row;
    break;
  case "Action":
    foreach (NSView subview in view.Subviews) {
      var btn = subview as NSButton;
      if (btn != null) {
        btn.Tag = row;
      }
    }
    break;
  }

  return view;
}

Examinons plus en détail plusieurs sections de ce code. Tout d’abord, si une nouvelle NSTableViewCell action est créée est effectuée en fonction du nom de la colonne. Pour les deux premières colonnes (Product et Details), la nouvelle ConfigureTextField méthode est appelée.

Pour la colonne Action , un nouveau NSButton est créé et ajouté à la cellule en tant que sous-affichage :

// Create new button
var button = new NSButton (new CGRect (0, 0, 81, 16));
button.SetButtonType (NSButtonType.MomentaryPushIn);
button.Title = "Delete";
button.Tag = row;
...

// Add to view
view.AddSubview (button);

La propriété du Tag bouton est utilisée pour contenir le nombre de lignes en cours de traitement. Ce nombre sera utilisé ultérieurement lorsque l’utilisateur demande la suppression d’une ligne dans l’événement du Activated bouton :

// Wireup events
button.Activated += (sender, e) => {
  // Get button and product
  var btn = sender as NSButton;
  var product = DataSource.Products [(int)btn.Tag];

  // Configure alert
  var alert = new NSAlert () {
    AlertStyle = NSAlertStyle.Informational,
    InformativeText = $"Are you sure you want to delete {product.Title}? This operation cannot be undone.",
    MessageText = $"Delete {product.Title}?",
  };
  alert.AddButton ("Cancel");
  alert.AddButton ("Delete");
  alert.BeginSheetForResponse (Controller.View.Window, (result) => {
    // Should we delete the requested row?
    if (result == 1001) {
      // Remove the given row from the dataset
      DataSource.Products.RemoveAt((int)btn.Tag);
      Controller.ReloadTable ();
    }
  });
};

Au début du gestionnaire d’événements, nous obtenons le bouton et le produit qui se trouve sur la ligne de table donnée. Ensuite, une alerte est présentée à l’utilisateur confirmant la suppression de ligne. Si l’utilisateur choisit de supprimer la ligne, la ligne donnée est supprimée de la source de données et la table est rechargée :

// Remove the given row from the dataset
DataSource.Products.RemoveAt((int)btn.Tag);
Controller.ReloadTable ();

Enfin, si la cellule Table View est réutilisée au lieu d’être créée, le code suivant le configure en fonction de la colonne en cours de traitement :

// Setup view based on the column selected
switch (tableColumn.Title) {
case "Product":
  view.ImageView.Image = NSImage.ImageNamed ("tag.png");
  view.TextField.StringValue = DataSource.Products [(int)row].Title;
  view.TextField.Tag = row;
  break;
case "Details":
  view.TextField.StringValue = DataSource.Products [(int)row].Description;
  view.TextField.Tag = row;
  break;
case "Action":
  foreach (NSView subview in view.Subviews) {
    var btn = subview as NSButton;
    if (btn != null) {
      btn.Tag = row;
    }
  }
  break;
}

Pour la colonne Action, toutes les sous-vues sont analysées jusqu’à ce qu’elles TagNSButton soient trouvées, puis la propriété est mise à jour pour pointer vers la ligne actuelle.

Avec ces modifications en place, lorsque l’application est exécutée, chaque ligne aura un bouton Supprimer :

Affichage de tableau avec boutons de suppression

Lorsque l’utilisateur clique sur un bouton Supprimer , une alerte s’affiche pour lui demander de supprimer la ligne donnée :

Alerte de suppression de ligne

Si l’utilisateur choisit de supprimer, la ligne sera supprimée et la table sera redessinée :

Tableau après la suppression de la ligne

Vues de table de liaison de données

En utilisant des techniques de codage clé-valeur et de liaison de données dans votre application Xamarin.Mac, vous pouvez réduire considérablement la quantité de code que vous devez écrire et gérer pour remplir et utiliser des éléments d’interface utilisateur. Vous bénéficiez également d’un découplage supplémentaire de vos données de stockage (modèle de données) de votre interface utilisateur frontale (modèle-vue-contrôleur), ce qui facilite la maintenance et la conception d’applications plus flexibles.

Le codage clé-valeur (KVC) est un mécanisme permettant d’accéder indirectement aux propriétés d’un objet, à l’aide de clés (chaînes spécialement mises en forme) pour identifier les propriétés au lieu de les accéder via des variables d’instance ou des méthodes d’accesseur (get/set). En implémentant des accesseurs conformes au codage clé-valeur dans votre application Xamarin.Mac, vous accédez à d’autres fonctionnalités macOS telles que l’observation de valeur clé (KVO), la liaison de données, les données principales, les liaisons Cocoa et la scriptabilité.

Pour plus d’informations, consultez la section Table View Data Binding de notre documentation sur la liaison de données et le codage clé-valeur.

Résumé

Cet article a examiné en détail l’utilisation des vues de table dans une application Xamarin.Mac. Nous avons vu les différents types et utilisations des vues de table, comment créer et gérer des vues de table dans le Générateur d’interface de Xcode et comment utiliser les vues de table dans le code C#.