Tabellenansichten in Xamarin.Mac

In diesem Artikel wird das Arbeiten mit Tabellenansichten in einer Xamarin.Mac-Anwendung behandelt. Es beschreibt das Erstellen von Tabellenansichten in Xcode und Interface Builder und die Interaktion mit ihnen im Code.

Wenn Sie mit C# und .NET in einer Xamarin.Mac-Anwendung arbeiten, haben Sie Zugriff auf die gleichen Tabellenansichten 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 Tabellenansichten zu erstellen und zu verwalten (oder optional direkt in C#-Code zu erstellen).

Eine Tabellenansicht zeigt Daten in einem tabellarischen Format an, das eine oder mehrere Informationsspalten in mehreren Zeilen enthält. Basierend auf dem Typ der zu erstellenden Tabellenansicht kann der Benutzer nach Spalten sortieren, Spalten neu organisieren, Spalten hinzufügen, Spalten entfernen oder die in der Tabelle enthaltenen Daten bearbeiten.

Eine Beispieltabelle

In diesem Artikel werden die Grundlagen der Arbeit mit Tabellenansichten 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 Tabellenansichten

Eine Tabellenansicht zeigt Daten in einem tabellarischen Format an, das eine oder mehrere Informationsspalten in mehreren Zeilen enthält. Tabellenansichten werden innerhalb von Bildlaufansichten (NSScrollView) angezeigt, und ab macOS 10.7 können Sie anstelle von Zellen (NSCell) beliebige Zeilen und Spalten anzeigenNSView. Sie können jedoch in der Regel eine Unterklasse NSTableCellView verwenden NSCell und Ihre benutzerdefinierten Zeilen und Spalten erstellen.

Eine Tabellenansicht speichert ihre eigenen Daten nicht, sondern basiert auf einer Datenquelle (NSTableViewDataSource), die sowohl die erforderlichen Zeilen als auch Spalten nach Bedarf bereitstellt.

Das Verhalten einer Tabellenansicht kann angepasst werden, indem eine Unterklasse des Tabellenansichtsdelegaten (NSTableViewDelegate) zur Unterstützung der Tabellenspaltenverwaltung, typisiert zum Auswählen von Funktionen, Zeilenauswahl und -bearbeitung, benutzerdefinierte Nachverfolgung und benutzerdefinierte Ansichten für einzelne Spalten und Zeilen bereitgestellt wird.

Beim Erstellen von Tabellenansichten schlägt Apple Folgendes vor:

  • Ermöglichen Sie dem Benutzer, die Tabelle zu sortieren, indem Sie auf eine Spaltenüberschrift klicken.
  • Erstellen Sie Spaltenüberschriften, bei denen es sich um Nomen oder kurze Nomenausdrücke handelt, die die in dieser Spalte angezeigten Daten beschreiben.

Weitere Informationen finden Sie im Abschnitt Inhaltsansichten der Os X Human Interface Guidelines von Apple.

Erstellen und Verwalten von Tabellenansichten in Xcode

Wenn Sie eine neue Xamarin.Mac Cocoa-Anwendung erstellen, erhalten Sie standardmäßig ein standardmäßig leeres Fenster. Dieses Fenster wird in einer .storyboard Datei definiert, die automatisch im Projekt enthalten ist. Doppelklicken Sie zum Bearbeiten des Windows-Entwurfs im Projektmappen-Explorer auf die Main.storyboard Datei:

Auswählen des Standard Storyboards

Dadurch wird das Fensterdesign im Xcode-Schnittstellen-Generator geöffnet:

Bearbeiten der Benutzeroberfläche in Xcode

Geben Sie table in das Suchfeld des Bibliotheksinspektors ein, um das Auffinden der Tabellenansichtssteuerelemente zu erleichtern:

Auswählen einer Tabellenansicht aus der Bibliothek

Ziehen Sie eine Tabellenansicht im Schnittstellen-Editor auf den Ansichtscontroller, füllen Sie den Inhaltsbereich des Ansichtscontrollers aus, und legen Sie sie dort fest, wo sie verkleinern und mit dem Fenster im Einschränkungs-Editor vergrößert wird:

Bearbeiten von Einschränkungen

Wählen Sie die Tabellenansicht in der Schnittstellenhierarchie aus, und die folgenden Eigenschaften sind im Attributinspektor verfügbar:

Screenshot: Verfügbare Eigenschaften im Attributinspektor

  • Inhaltsmodus : Ermöglicht die Verwendung von Ansichten (NSView) oder Zellen (NSCell), um die Daten in den Zeilen und Spalten anzuzeigen. Ab macOS 10.7 sollten Sie Ansichten verwenden.
  • Gleitkommagruppenzeilen : Wenn true, zeichnet die Tabellenansicht gruppierte Zellen so, als ob sie schweben.
  • Spalten : Definiert die Anzahl der angezeigten Spalten.
  • Header: Wenn true, verfügen die Spalten über Header.
  • Neuanordnung : Wenn true, kann der Benutzer die Spalten in der Tabelle neu anordnen.
  • Ändern der Größe : Wenn true, kann der Benutzer Spaltenüberschriften ziehen, um die Spaltengröße zu ändern.
  • Spaltengröße: Steuert die automatische Größe von Spalten in der Tabelle.
  • Hervorhebung : Steuert den Typ der Hervorhebung, die die Tabelle verwendet, wenn eine Zelle ausgewählt wird.
  • Alternative Zeilen : Wenn true, weist eine andere Zeile eine andere Hintergrundfarbe auf.
  • Horizontales Raster : Wählt den Typ des Rahmens aus, der horizontal zwischen Zellen gezeichnet wird.
  • Vertikales Raster : Wählt den Typ des Rahmens aus, der vertikal zwischen Zellen gezeichnet wird.
  • Rasterfarbe : Legt die Zellenrahmenfarbe fest.
  • Hintergrund : Legt die Hintergrundfarbe der Zelle fest.
  • Auswahl : Ermöglicht Ihnen, zu steuern, wie der Benutzer Zellen in der Tabelle wie folgt auswählen kann:
    • Mehrfach : Wenn true, kann der Benutzer mehrere Zeilen und Spalten auswählen.
    • Spalte : Wenn true, kann der Benutzer Spalten auswählen.
    • Geben Sie Auswählen ein: Wenn true, kann der Benutzer ein Zeichen eingeben, um eine Zeile auszuwählen.
    • Leer : Wenn trueder Benutzer keine Zeile oder Spalte auswählen muss, lässt die Tabelle überhaupt keine Auswahl zu.
  • Automatische Speicherung : Der Name, unter dem das Tabellenformat automatisch gespeichert wird.
  • Spalteninformationen : Wenn true, werden die Reihenfolge und Breite der Spalten automatisch gespeichert.
  • Zeilenumbrüche : Wählen Sie aus, wie die Zelle Zeilenumbrüche behandelt.
  • Schneidet die letzte sichtbare Zeile ab: Wenn truedie Zelle in den Daten abgeschnitten wird, kann nicht in ihre Grenzen passen.

Wichtig

Es sei denn, Sie verwalten eine ältere Xamarin.Mac-Anwendung, NSView sollten basierende Tabellenansichten über basierende NSCell Tabellenansichten verwendet werden. NSCell gilt als legacy und wird möglicherweise in Zukunft nicht mehr unterstützt.

Wählen Sie eine Tabellenspalte in der Schnittstellenhierarchie aus , und die folgenden Eigenschaften sind im Attributinspektor verfügbar:

Screenshot: Verfügbare Eigenschaften für eine Tabellenspalte im Attributinspektor

  • Titel : Legt den Titel der Spalte fest.
  • Ausrichtung : Legt die Ausrichtung des Texts innerhalb der Zellen fest.
  • Titelschriftart : Wählt die Schriftart für den Headertext der Zelle aus.
  • Sortierschlüssel : Der Schlüssel, der zum Sortieren von Daten in der Spalte verwendet wird. Lassen Sie leer, wenn der Benutzer diese Spalte nicht sortieren kann.
  • Selektor : Die Aktion , die zum Ausführen der Sortierung verwendet wird. Lassen Sie leer, wenn der Benutzer diese Spalte nicht sortieren kann.
  • Reihenfolge : Die Sortierreihenfolge für die Spaltendaten.
  • Größenänderung : Wählt den Typ der Größenänderung für die Spalte aus.
  • Bearbeitbar : Wenn true, kann der Benutzer Zellen in einer zellenbasierten Tabelle bearbeiten.
  • Ausgeblendet : Wenn true, ist die Spalte ausgeblendet.

Sie können die Größe der Spalte auch ändern, indem Sie den Ziehpunkt (vertikal zentriert auf der rechten Seite der Spalte) nach links oder rechts ziehen.

Wählen Sie die einzelnen Spalten in der Tabellenansicht aus, und weisen Sie der ersten Spalte den Titel und Product die zweite spalte zu Details.

Wählen Sie eine Tabellenzellenansicht (NSTableViewCell) in der Schnittstellenhierarchie aus, und die folgenden Eigenschaften sind im Attributinspektor verfügbar:

Screenshot: Verfügbare Eigenschaften für eine Tabellenzellenansicht im Attributinspektor

Dies sind alle Eigenschaften einer Standardansicht. Sie haben auch die Möglichkeit, die Größe der Zeilen für diese Spalte hier zu ändern.

Wählen Sie eine Tabellenansichtszelle (standardmäßig ist dies ein NSTextField) in der Schnittstellenhierarchie aus, und die folgenden Eigenschaften sind im Attributinspektor verfügbar:

Screenshot: Verfügbare Eigenschaften für eine Tabellenansichtszelle im Attributinspektor

Hier müssen alle Eigenschaften eines Standardtextfelds festgelegt werden. Standardmäßig wird ein Standardtextfeld verwendet, um Daten für eine Zelle in einer Spalte anzuzeigen.

Wählen Sie eine Tabellenzellenansicht (NSTableFieldCell) in der Schnittstellenhierarchie aus, und die folgenden Eigenschaften sind im Attributinspektor verfügbar:

Screenshot: Verfügbare Eigenschaften für eine andere Tabellenansichtszelle im Attributinspektor

Die wichtigsten Einstellungen sind hier:

  • Layout : Wählen Sie aus, wie Zellen in dieser Spalte angeordnet werden.
  • Verwendet den Einzelzeilenmodus : Wenn true, ist die Zelle auf eine einzelne Zeile beschränkt.
  • Breite des ersten Laufzeitlayouts : Wenn true, bevorzugt die Zelle die für sie festgelegte Breite (entweder manuell oder automatisch), wenn sie bei der ersten Ausführung der Anwendung angezeigt wird.
  • Aktion : Steuert, wann die Bearbeitungsaktion für die Zelle gesendet wird.
  • Verhalten : Definiert, ob eine Zelle auswählbar oder bearbeitbar ist.
  • Rich Text : Wenn true, kann die Zelle formatierten und formatierten Text anzeigen.
  • Rückgängig : Wenn true, übernimmt die Zelle die Verantwortung für das Rückgängig-Verhalten.

Wählen Sie die Tabellenzellenansicht (NSTableFieldCell) am unteren Rand einer Tabellenspalte in der Schnittstellenhierarchie aus:

Auswählen der Tabellenzellenansicht

Dadurch können Sie die Tabellenzellenansicht bearbeiten, die als Basismuster für alle Zellen verwendet wird, die für die angegebene Spalte erstellt wurden.

Hinzufügen von Aktionen und Outlets

Genau wie jedes andere Cocoa UI-Steuerelement müssen wir unsere Tabellenansicht und ihre Spalten und Zellen für C#-Code mit Aktionen und Outlets verfügbar machen (basierend auf der erforderlichen Funktionalität).

Der Prozess ist für alle Tabellenansichtselemente, die wir verfügbar machen möchten, identisch:

  1. Wechseln Sie zum Assistenten-Editor , und stellen Sie sicher, dass die ViewController.h Datei ausgewählt ist:

    Der Assistent-Editor

  2. Wählen Sie in der Schnittstellenhierarchie die Tabellenansicht aus, klicken Sie bei gedrückter Ctrl-Taste, und ziehen Sie sie auf die ViewController.h Datei.

  3. Erstellen Sie einen Outlet für die Tabellenansicht namens ProductTable:

    Screenshot: Eine Outlet-Verbindung, die für die Tabellenansicht mit dem Namen ProductTable erstellt wurde.

  4. Erstellen Sie Outlets für die Tabellenspalten mit dem Namen ProductColumn und DetailsColumn:

    Screenshot: Outlet-Verbindungen, die für andere Tabellenansichten erstellt wurden

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

Als Nächstes schreiben wir den Code, der einige Daten für die Tabelle anzeigt, wenn die Anwendung ausgeführt wird.

Auffüllen der Tabellenansicht

Mit unserer Tabellenansicht, die im Schnittstellen-Generator entworfen und über ein Outlet verfügbar gemacht wurde, müssen wir als Nächstes den C#-Code erstellen, um sie aufzufüllen.

Zunächst erstellen wir eine neue Product Klasse, die die Informationen für die einzelnen Zeilen 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 Product als Namen ein, und klicken Sie auf die Schaltfläche Neu:

Erstellen einer leeren Klasse

Lassen Sie die Product.cs Datei wie folgt aussehen:

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

Als Nächstes müssen wir eine Unterklasse von NSTableDataSource erstellen, um die Daten für unsere Tabelle bereitzustellen, während sie angefordert wird. 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 ProductTableDataSource als Namen ein, und klicken Sie auf die Schaltfläche Neu.

Bearbeiten Sie die ProductTableDataSource.cs Datei, und lassen Sie sie wie folgt aussehen:

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

Diese Klasse verfügt über Speicher für die Elemente der Tabellenansicht und überschreibt das GetRowCount , um die Anzahl der Zeilen in der Tabelle zurückzugeben.

Schließlich müssen wir eine Unterklasse von NSTableDelegate erstellen, um das Verhalten für unsere Tabelle bereitzustellen. 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 ProductTableDelegate als Namen ein, und klicken Sie auf die Schaltfläche Neu.

Bearbeiten Sie die ProductTableDelegate.cs Datei, und lassen Sie sie wie folgt aussehen:

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

Wenn wir eine instance von ProductTableDelegateerstellen, übergeben wir auch eine instance der, die ProductTableDataSource die Daten für die Tabelle bereitstellt. Die GetViewForItem -Methode ist dafür verantwortlich, eine Ansicht (Daten) zurückzugeben, um die Zelle für eine Give-Spalte und -Zeile anzuzeigen. Wenn möglich, wird eine vorhandene Ansicht wiederverwendet, um die Zelle anzuzeigen. Andernfalls muss eine neue Ansicht erstellt werden.

Um die Tabelle aufzufüllen, bearbeiten wir die ViewController.cs Datei und lassen die AwakeFromNib Methode wie folgt aussehen:

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

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

Screenshot: Fenster mit dem Namen Product Table mit drei Einträgen

Sortieren nach Spalte

Wir erlauben dem Benutzer, die Daten in der Tabelle zu sortieren, indem er auf eine Spaltenüberschrift klickt. Doppelklicken Sie zunächst auf die Datei, um sie für die Main.storyboard Bearbeitung im Schnittstellen-Generator zu öffnen. Wählen Sie die Product Spalte aus, geben Sie Title für den Sortierschlüssel, für den Selektor ein, compare: und wählen Sie für die Bestellung folgendes aus:Ascending

Screenshot: Schnittstellen-Generator, in dem Sie den Sortierschlüssel für die Spalte Product festlegen können.

Wählen Sie die Details Spalte aus, geben Sie Description für den Sortierschlüssel, für den Selektor ein, compare: und wählen Sie für die Bestellung folgendes aus:Ascending

Screenshot: Schnittstellen-Generator, in dem Sie den Sortierschlüssel für die Spalte Details festlegen können.

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

Nun bearbeiten wir die ProductTableDataSource.cs Datei und fügen die folgenden Methoden hinzu:

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

Die Sort -Methode ermöglicht es uns, die Daten in der Datenquelle basierend auf einem bestimmten Product Klassenfeld in aufsteigender oder absteigender Reihenfolge zu sortieren. Die überschriebene SortDescriptorsChanged Methode wird bei jeder Verwendung von Klicks auf eine Spaltenüberschrift aufgerufen. Es wird der Schlüsselwert übergeben, den wir im Schnittstellen-Generator festgelegt haben, und die Sortierreihenfolge für diese Spalte.

Wenn wir die Anwendung ausführen und auf die Spaltenheader klicken, werden die Zeilen nach dieser Spalte sortiert:

Eine Beispiel-App-Ausführung

Zeilenauswahl

Wenn Sie dem Benutzer erlauben möchten, eine einzelne Zeile auszuwählen, doppelklicken Sie auf die Datei, um sie für die Main.storyboard Bearbeitung im Schnittstellen-Generator zu öffnen. Wählen Sie die Tabellenansicht in der Schnittstellenhierarchie aus, und deaktivieren Sie das Kontrollkästchen Mehrere im Attributinspektor:

Screenshot: Schnittstellen-Generator, in dem Sie im Attributinspektor Mehrere auswählen können.

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

Bearbeiten Sie als Nächstes die ProductTableDelegate.cs Datei, und fügen Sie die folgende Methode hinzu:

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

Dadurch kann der Benutzer eine einzelne Zeile in der Tabellenansicht auswählen. Kehren Sie false für jede ShouldSelectRow Zeile zurück, die der Benutzer nicht auswählen kann, oder false für jede Zeile, wenn sie nicht möchten, dass der Benutzer Zeilen auswählen kann.

Die Tabellenansicht (NSTableView) enthält die folgenden Methoden zum Arbeiten mit der Zeilenauswahl:

  • DeselectRow(nint) – Hebt die Auswahl der angegebenen Zeile in der Tabelle auf.
  • SelectRow(nint,bool) – Wählt die angegebene Zeile aus. Übergeben Sie false den zweiten Parameter, um jeweils nur eine Zeile auszuwählen.
  • SelectedRow – Gibt die aktuelle Zeile zurück, die in der Tabelle ausgewählt ist.
  • IsRowSelected(nint) – Gibt zurück true , wenn die angegebene Zeile ausgewählt ist.

Auswahl mehrerer Zeilen

Wenn Sie dem Benutzer erlauben möchten, mehrere Zeilen auszuwählen, doppelklicken Sie auf die Datei, um sie für die Main.storyboard Bearbeitung im Schnittstellen-Generator zu öffnen. Wählen Sie die Tabellenansicht in der Schnittstellenhierarchie aus, und aktivieren Sie das Kontrollkästchen Mehrere im Attributinspektor:

Screenshot des Schnittstellen-Generators, in dem Sie Mehrere auswählen können, um die Auswahl mehrerer Zeilen zuzulassen.

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

Bearbeiten Sie als Nächstes die ProductTableDelegate.cs Datei, und fügen Sie die folgende Methode hinzu:

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

Dadurch kann der Benutzer eine einzelne Zeile in der Tabellenansicht auswählen. Kehren Sie false für jede ShouldSelectRow Zeile zurück, die der Benutzer nicht auswählen kann, oder false für jede Zeile, wenn sie nicht möchten, dass der Benutzer Zeilen auswählen kann.

Die Tabellenansicht (NSTableView) enthält die folgenden Methoden zum Arbeiten mit der Zeilenauswahl:

  • DeselectAll(NSObject) – Hebt die Auswahl aller Zeilen in der Tabelle auf. Verwenden Sie this für den ersten Parameter, um das Objekt zu senden, das die Auswahl ausführt.
  • DeselectRow(nint) – Hebt die Auswahl der angegebenen Zeile in der Tabelle auf.
  • SelectAll(NSobject) – Wählt alle Zeilen in der Tabelle aus. Verwenden Sie this für den ersten Parameter, um das Objekt zu senden, das die Auswahl ausführt.
  • SelectRow(nint,bool) – Wählt die angegebene Zeile aus. Übergeben Sie false für den zweiten Parameter, um die Auswahl zu löschen, und wählen Sie nur eine einzelne Zeile aus, übergeben Sie true , um die Auswahl zu erweitern und diese Zeile einzuschließen.
  • SelectRows(NSIndexSet,bool) – Wählt den angegebenen Zeilensatz aus. Übergeben Sie false für den zweiten Parameter, um die Auswahl zu löschen, und wählen Sie nur diese Zeilen aus, übergeben true Sie, um die Auswahl zu erweitern und diese Zeilen einzuschließen.
  • SelectedRow – Gibt die aktuelle Zeile zurück, die in der Tabelle ausgewählt ist.
  • SelectedRows - Gibt einen NSIndexSet zurück, der die Indizes der ausgewählten Zeilen enthält.
  • SelectedRowCount – Gibt die Anzahl der ausgewählten Zeilen zurück.
  • IsRowSelected(nint) – Gibt zurück true , wenn die angegebene Zeile ausgewählt ist.

Geben Sie zum Auswählen der Zeile ein.

Wenn Sie es dem Benutzer ermöglichen möchten, ein Zeichen mit ausgewählter Tabellenansicht einzugeben und die erste Zeile mit diesem Zeichen auszuwählen, doppelklicken Sie auf die Main.storyboard Datei, um sie zur Bearbeitung im Schnittstellen-Generator zu öffnen. Wählen Sie die Tabellenansicht in der Schnittstellenhierarchie aus, und aktivieren Sie das Kontrollkästchen Typ auswählen im Attributinspektor:

Festlegen des Auswahltyps

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

Nun bearbeiten wir die ProductTableDelegate.cs Datei und fügen die folgende Methode hinzu:

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

Die GetNextTypeSelectMatch -Methode übernimmt die angegebene searchString und gibt die Zeile der ersten Product zurück, in der diese Zeichenfolge enthalten ist Title.

Wenn wir die Anwendung ausführen und ein Zeichen eingeben, wird eine Zeile ausgewählt:

Screenshot: Ergebnis der Ausführung der Anwendung

Neuanordnen von Spalten

Wenn Sie dem Benutzer das Ziehen von Neuanordnungsspalten in der Tabellenansicht ermöglichen möchten, doppelklicken Sie auf die Datei, um sie für die Main.storyboard Bearbeitung im Schnittstellen-Generator zu öffnen. Wählen Sie die Tabellenansicht in der Schnittstellenhierarchie aus, und aktivieren Sie das Kontrollkästchen Neu anordnen im Attributinspektor:

Screenshot: Schnittstellen-Generator, in dem Sie im Attributinspektor die Option Neuodering auswählen können.

Wenn wir einen Wert für die Autosave-Eigenschaft angeben und das Feld Spalteninformationen überprüfen, werden alle Änderungen, die wir am Layout der Tabelle vornehmen, automatisch für uns gespeichert und bei der nächsten Ausführung der Anwendung wiederhergestellt.

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

Nun bearbeiten wir die ProductTableDelegate.cs Datei und fügen die folgende Methode hinzu:

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

Die ShouldReorder -Methode sollte für jede Spalte zurückgeben true , die sie zulassen möchte, dass sie neu in die newColumnIndex- andernfalls zurückgeben falsekann .

Wenn wir die Anwendung ausführen, können wir Spaltenüberschriften ziehen, um unsere Spalten neu anzuordnen:

Beispiel für die neu sortierten Spalten

Zellen bearbeiten

Wenn Sie dem Benutzer erlauben möchten, die Werte für eine bestimmte Zelle zu bearbeiten, bearbeiten Sie die ProductTableDelegate.cs Datei, und ändern Sie die GetViewForItem Methode wie folgt:

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

Wenn wir nun die Anwendung ausführen, kann der Benutzer die Zellen in der Tabellenansicht bearbeiten:

Ein Beispiel für das Bearbeiten einer Zelle

Verwenden von Bildern in Tabellenansichten

Um ein Bild als Teil der Zelle in ein NSTableVieweinzuschließen, müssen Sie ändern, wie die Daten von der -Methode der TabellenansichtGetViewForItemNSTableViewDelegate'szurückgegeben werden, um anstelle NSTableCellView der typischen NSTextFieldzu verwenden. Beispiel:

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

Weitere Informationen finden Sie im Abschnitt Verwenden von Bildern mit Tabellenansichten der Dokumentation Arbeiten mit Bildern .

Hinzufügen einer Schaltfläche "Löschen" zu einer Zeile

Basierend auf den Anforderungen Ihrer App kann es vorkommen, dass Sie für jede Zeile in der Tabelle eine Aktionsschaltfläche bereitstellen müssen. Als Beispiel hierfür erweitern wir das oben erstellte Tabellenansichtsbeispiel, um eine Schaltfläche Löschen in jede Zeile einzuschließen.

Bearbeiten Sie zunächst im Main.storyboard Schnittstellen-Generator von Xcode, wählen Sie die Tabellenansicht aus, und erhöhen Sie die Anzahl der Spalten auf drei (3). Ändern Sie als Nächstes den Titel der neuen Spalte in Action:

Bearbeiten des Spaltennamens

Speichern Sie die Änderungen im Storyboard, und kehren Sie zu Visual Studio für Mac zurück, um die Änderungen zu synchronisieren.

Bearbeiten Sie als Nächstes die ViewController.cs Datei, und fügen Sie die folgende öffentliche Methode hinzu:

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

Ändern Sie in derselben Datei die Erstellung des neuen Tabellenansichtsdelegaten in der ViewDidLoad -Methode wie folgt:

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

Bearbeiten Sie nun die ProductTableDelegate.cs Datei, um eine private Verbindung mit dem Ansichtscontroller aufzunehmen und den Controller beim Erstellen eines neuen instance des Delegaten als Parameter zu verwenden:

#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

Fügen Sie als Nächstes der -Klasse die folgende neue private Methode hinzu:

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

Dies übernimmt alle Textansichtskonfigurationen, die zuvor in der GetViewForItem -Methode ausgeführt wurden, und platziert sie an einer einzigen, aufrufbaren Position (da die letzte Spalte der Tabelle keine Textansicht, sondern eine Schaltfläche enthält).

Bearbeiten Sie schließlich die GetViewForItem -Methode, und lassen Sie sie wie folgt aussehen:

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

Sehen wir uns einige Abschnitte dieses Codes genauer an. Wenn ein neues NSTableViewCell erstellt wird, wird zunächst eine Aktion basierend auf dem Namen der Spalte ausgeführt. Für die ersten beiden Spalten (Product und Details) wird die neue ConfigureTextField Methode aufgerufen.

Für die Spalte Aktion wird ein neues NSButton erstellt und der Zelle als Unteransicht hinzugefügt:

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

Die Button-Eigenschaft Tag wird verwendet, um die Nummer der Zeile zu speichern, die derzeit verarbeitet wird. Diese Nummer wird später verwendet, wenn der Benutzer die Löschung einer Zeile im Button-Ereignis Activated anfordert:

// 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 ();
    }
  });
};

Am Anfang des Ereignishandlers erhalten wir die Schaltfläche und das Produkt, das sich in der angegebenen Tabellenzeile befindet. Anschließend wird dem Benutzer eine Warnung angezeigt, die den Zeilenlöschvorgang bestätigt. Wenn der Benutzer die Zeile löschen möchte, wird die angegebene Zeile aus der Datenquelle entfernt, und die Tabelle wird erneut geladen:

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

Wenn schließlich die Tabellenansichtszelle wiederverwendet wird, anstatt neu erstellt zu werden, konfiguriert der folgende Code sie basierend auf der zu verarbeitenden Spalte:

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

Für die Spalte Aktion werden alle Unteransichten überprüft, bis gefunden NSButton wird. Anschließend wird die Tag -Eigenschaft aktualisiert, um auf die aktuelle Zeile zu zeigen.

Wenn diese Änderungen vorgenommen wurden, verfügt jede Zeile beim Ausführen der App über die Schaltfläche Löschen :

Die Tabellenansicht mit Schaltflächen zum Löschen

Wenn der Benutzer auf eine Schaltfläche Löschen klickt, wird eine Warnung angezeigt, in der er aufgefordert wird, die angegebene Zeile zu löschen:

Warnung zum Löschen von Zeilen

Wenn der Benutzer löschen auswäht, wird die Zeile entfernt, und die Tabelle wird neu gezeichnet:

Die Tabelle nach dem Löschen der Zeile

Datenbindungstabellensichten

Durch die Verwendung Key-Value Codierungs- und Datenbindungstechniken in Ihrer Xamarin.Mac-Anwendung können Sie die Menge an Code, den Sie schreiben und verwalten müssen, um Benutzeroberflächenelemente aufzufüllen und zu arbeiten, erheblich verringern. Sie haben auch den Vorteil, Dass Ihre Sicherungsdaten (Datenmodell) weiter von Ihrer Front-End-Benutzeroberfläche (Model-View-Controller) entkoppelt werden, was zu einem einfacheren, flexibleren Anwendungsentwurf führt.

Key-Value Coding (KVC) ist ein Mechanismus für den indirekten Zugriff auf die Eigenschaften eines Objekts, wobei Schlüssel (speziell formatierte Zeichenfolgen) verwendet werden, um Eigenschaften zu identifizieren, anstatt über instance Variablen oder Accessormethoden (get/set) darauf zuzugreifen. Durch die Implementierung von Key-Value Coding-kompatiblen Accessoren in Ihrer Xamarin.Mac-Anwendung erhalten Sie Zugriff auf andere macOS-Features wie Key-Value Observing (KVO), Datenbindung, Kerndaten, Cocoa-Bindungen und Skriptierbarkeit.

Weitere Informationen finden Sie im Abschnitt Datenbindung in der Tabellenansicht in unserer Dokumentation zur Datenbindung und Key-Value Codierung .

Zusammenfassung

In diesem Artikel wird die Arbeit mit Tabellenansichten in einer Xamarin.Mac-Anwendung ausführlich erläutert. Wir haben die verschiedenen Typen und Verwendungen von Tabellenansichten, das Erstellen und Verwalten von Tabellenansichten im Schnittstellen-Generator von Xcode und das Arbeiten mit Tabellenansichten in C#-Code gesehen.