Zobrazení tabulek v Xamarin.Mac

Tento článek popisuje práci se zobrazeními tabulek v aplikaci Xamarin.Mac. Popisuje vytváření zobrazení tabulek v Xcode a Interface Builderu a interakci s nimi v kódu.

Při práci s jazykem C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným zobrazením tabulek, ve Objective-C kterých vývojář pracuje, a Xcode . Vzhledem k tomu, že se Xamarin.Mac integruje přímo s Xcode, můžete pomocí Tvůrce rozhraní Xcode vytvářet a udržovat zobrazení tabulky (nebo je volitelně vytvořit přímo v kódu jazyka C#).

Zobrazení tabulky zobrazuje data v tabulkovém formátu obsahujícím jeden nebo více sloupců informací v několika řádcích. Na základě typu vytvářeného zobrazení tabulky může uživatel řadit podle sloupců, měnit uspořádání sloupců, přidávat sloupce, odebírat sloupce nebo upravovat data obsažená v tabulce.

An example table

V tomto článku se podíváme na základy práce se zobrazeními tabulek v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste si nejprve prošli článek Hello, Mac , konkrétně úvod do Xcode a Tvůrce rozhraní a výstupy a akce , protože se zabývá klíčovými koncepty a technikami, které budeme používat v tomto článku.

Možná se také budete chtít podívat na oddíly v dokumentu Interní dokumenty Xamarin.Mac pro zveřejnění tříd a metodObjective-Cjazyka C#. Vysvětluje také, které Register příkazy a Export které se používají k připojení tříd jazyka C# k Objective-C objektům a prvkům uživatelského rozhraní.

Úvod do zobrazení tabulek

Zobrazení tabulky zobrazuje data v tabulkovém formátu obsahujícím jeden nebo více sloupců informací v několika řádcích. Zobrazení tabulky se zobrazují uvnitř zobrazení posouvání (NSScrollView) a počínaje macOS 10.7 můžete k zobrazení řádků i sloupců použít libovolnou NSView možnost místo buněk (NSCell). To znamená, že můžete přesto použít NSCell podtřídu NSTableCellView a vytvořit vlastní řádky a sloupce.

Zobrazení tabulky neukládá vlastní data, místo toho spoléhá na zdroj dat (NSTableViewDataSource) k poskytnutí požadovaných řádků i sloupců podle potřeby.

Chování zobrazení tabulky lze přizpůsobit tak, že poskytuje podtřídu delegáta zobrazení tabulky (NSTableViewDelegate) pro podporu správy sloupců tabulky, typ pro výběr funkcí, výběr řádků a úpravy, vlastní sledování a vlastní zobrazení pro jednotlivé sloupce a řádky.

Při vytváření zobrazení tabulky navrhuje Apple následující:

  • Umožňuje uživateli seřadit tabulku kliknutím na záhlaví sloupců.
  • Vytvořte záhlaví sloupců, která jsou podstatná jména nebo krátké fráze podstatných jmen, které popisují data zobrazená v tomto sloupci.

Další informace najdete v části Zobrazení obsahu pokynů apple pro lidské rozhraní OS X.

Vytváření a údržba zobrazení tabulek v Xcode

Když vytvoříte novou aplikaci Xamarin.Mac Cocoa, ve výchozím nastavení se zobrazí standardní prázdné okno. Tato okna jsou definována .storyboard v souboru, který je automaticky zahrnutý v projektu. Pokud chcete upravit návrh oken, poklikejte v Průzkumník řešení na Main.storyboard soubor:

Selecting the main storyboard

Otevře se návrh okna v Tvůrci rozhraní Xcode:

Editing the UI in Xcode

Zadejte table do vyhledávacího pole inspektoru knihovny, abyste usnadnili vyhledání ovládacích prvků Zobrazení tabulky:

Selecting a Table View from the Library

Přetáhněte zobrazení tabulky do kontroleru zobrazení v editoru rozhraní, aby vyplnil oblast obsahu kontroleru zobrazení a nastavte ho na místo, kde se zmenší a zvětší s oknem v Editoru omezení:

Editing constraints

V hierarchii rozhraní vyberte zobrazení tabulky a v inspektoru atributů jsou k dispozici následující vlastnosti:

Screenshot shows the properties available in the Attribute Inspector.

  • Režim obsahu – Umožňuje použít zobrazení (NSView) nebo buňky (NSCell) k zobrazení dat v řádcích a sloupcích. Počínaje macOS 10.7 byste měli používat zobrazení.
  • Plovoucí řady seskupí řádky – Pokud truebude zobrazení tabulky nakreslit seskupené buňky, jako by byly plovoucí.
  • Sloupce – definuje počet zobrazených sloupců.
  • Záhlaví – Pokud truebudou sloupce obsahovat záhlaví.
  • Změna pořadí – Pokud truebude uživatel moct přeuspořádat sloupce v tabulce.
  • Změna velikosti – Pokud truebude uživatel moct přetáhnout záhlaví sloupců, aby změnil velikost sloupců.
  • Nastavení velikosti sloupce – Určuje, jak bude tabulka automaticky měnit velikost sloupců.
  • Zvýraznění – určuje typ zvýraznění tabulky, která se používá při výběru buňky.
  • Alternativní řádky – Pokud true, někdy jiný řádek bude mít jinou barvu pozadí.
  • Vodorovná mřížka – vybere typ ohraničení nakresleného mezi buňkami vodorovně.
  • Svislá mřížka – vybere typ ohraničení nakresleného mezi buňkami svisle.
  • Barva mřížky – Nastaví barvu ohraničení buňky.
  • Pozadí – Nastaví barvu pozadí buňky.
  • Výběr – Umožňuje řídit, jak může uživatel vybrat buňky v tabulce jako:
    • Násobek – Pokud truemůže uživatel vybrat více řádků a sloupců.
    • Sloupec – Pokud trueuživatel může vybrat sloupce.
    • Zadejte Select - If true, uživatel může zadat znak pro výběr řádku.
    • Prázdné – Pokud trueuživatel nemusí vybrat řádek nebo sloupec, tabulka neumožňuje vůbec žádný výběr.
  • Automatické ukládání – název, pod kterým se automaticky uloží formát tabulek.
  • Informace o sloupci – Pokud truese pořadí a šířka sloupců automaticky uloží.
  • Konce řádků – Vyberte, jak buňka zpracovává konce řádků.
  • Zkrátí poslední viditelnou čáru – pokud truese buňka zkrátí v datech, nemůže se vejít do hranic.

Důležité

Pokud si nechováte starší aplikaci Xamarin.Mac, NSView měla by se v zobrazeních tabulek založená na základě použít NSCell zobrazení tabulek. NSCell se považuje za starší verzi a v budoucnu se nemusí podporovat.

V hierarchii rozhraní vyberte sloupec tabulky a v inspektoru atributů jsou k dispozici následující vlastnosti:

Screenshot shows the properties available for a Table Column in the Attribute Inspector.

  • Název – Nastaví název sloupce.
  • Zarovnání – nastavte zarovnání textu v buňkách.
  • Písmo nadpisu – vybere písmo pro text záhlaví buňky.
  • Klíč řazení – je klíč použitý k řazení dat ve sloupci. Pokud uživatel nemůže tento sloupec seřadit, nechejte prázdné.
  • Selektor – používá se akce k řazení. Pokud uživatel nemůže tento sloupec seřadit, nechejte prázdné.
  • Pořadí – je pořadí řazení dat sloupců.
  • Změna velikosti – Vybere typ změny velikosti sloupce.
  • Upravitelné – Pokud truemůže uživatel upravovat buňky v tabulce založené na buňkách.
  • Skrytý – Pokud trueje sloupec skrytý.

Velikost sloupce můžete změnit také přetažením úchytu (svisle na střed na pravé straně sloupce) doleva nebo doprava.

Pojďme vybrat každý sloupec v zobrazení tabulky a dát prvnímu sloupci názevProduct a druhý sloupec Details.

V hierarchii rozhraní vyberte zobrazení buňky tabulky (NSTableViewCell) a v inspektoru atributů jsou k dispozici následující vlastnosti:

Screenshot shows the properties available for a Table Cell View in the Attribute Inspector.

Toto jsou všechny vlastnosti standardního zobrazení. Tady máte také možnost upravit velikost řádků pro tento sloupec.

Vyberte buňku zobrazení tabulky (ve výchozím nastavení je NSTextFieldto ) v hierarchii rozhraní a v inspektoru atributů jsou k dispozici následující vlastnosti:

Screenshot shows the properties available for a Table View Cell in the Attribute Inspector.

Tady budete mít všechny vlastnosti standardního textového pole. Ve výchozím nastavení se standardní textové pole používá k zobrazení dat pro buňku ve sloupci.

V hierarchii rozhraní vyberte zobrazení buňky tabulky (NSTableFieldCell) a v inspektoru atributů jsou k dispozici následující vlastnosti:

Screenshot shows the properties available for a different Table View Cell in the Attribute Inspector.

Nejdůležitější nastavení jsou:

  • Rozložení – Vyberte způsob rozložení buněk v tomto sloupci.
  • Používá režim s jedním řádkem – Pokud trueje buňka omezena na jeden řádek.
  • První šířka rozložení modulu runtime – Pokud truebude buňka upřednostňovat šířku nastavenou (ručně nebo automaticky), když se zobrazí při prvním spuštění aplikace.
  • Akce – určuje, kdy se pro buňku odešle akce pro úpravy.
  • Chování – definuje, jestli je buňka vybratelná nebo upravitelná.
  • Formátovaný text – Pokud truemůže buňka zobrazit formátovaný a stylovaný text.
  • Zpět - Pokud truebuňka přebírá odpovědnost za chování vrácení zpět.

Vyberte zobrazení buňky tabulky (NSTableFieldCell) v dolní části sloupce tabulky v hierarchii rozhraní:

Selecting the Table Cell View

To vám umožní upravit zobrazení buněk tabulky použité jako základní vzor pro všechny buňky vytvořené pro daný sloupec.

Přidání akcí a výstupů

Stejně jako jakýkoli jiný ovládací prvek uživatelského rozhraní Cocoa potřebujeme zveřejnit zobrazení tabulky a je to sloupce a buňky kódu jazyka C# pomocí akcí a výstupů (na základě požadovaných funkcí).

Tento proces je stejný pro všechny elementy Table View, které chceme zveřejnit:

  1. Přepněte do Editoru asistentů a ujistěte se, že ViewController.h je vybraný soubor:

    The Assistant Editor

  2. V hierarchii rozhraní vyberte zobrazení tabulky, klikněte na něj a přetáhněte ho ViewController.h do souboru.

  3. Vytvořte výstup pro zobrazení tabulky s názvem ProductTable:

    Screenshot shows an Outlet connection created for the Table View named ProductTable.

  4. Vytvořit výstupy pro sloupce tabulek, které jsou také volány ProductColumn a DetailsColumn:

    Screenshot shows an Outlet connections created for other Table Views.

  5. Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

V dalším kroku napíšeme kód, který při spuštění aplikace zobrazí nějaká data pro tabulku.

Naplnění zobrazení tabulky

S naším zobrazením tabulky navrženým v Tvůrci rozhraní a vystaveným prostřednictvím výstupu musíme vytvořit kód jazyka C#, který ho naplní.

Nejprve vytvoříme novou Product třídu, která bude obsahovat informace pro jednotlivé řádky. V Průzkumník řešení klikněte pravým tlačítkem na Projekt a vyberte Přidat>nový soubor... Vyberte položku Obecné>prázdné třídy, zadejte Product název a klikněte na tlačítko Nový:

Creating an empty class

Udělejte soubor Product.cs takto:

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

Dále musíme vytvořit podtřídu, která NSTableDataSource bude poskytovat data pro naši tabulku, jak je požadována. V Průzkumník řešení klikněte pravým tlačítkem na Projekt a vyberte Přidat>nový soubor... Vyberte Obecné>prázdné třídy, zadejte ProductTableDataSource název a klikněte na tlačítko Nový.

ProductTableDataSource.cs Upravte soubor a udělejte ho takto:

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

Tato třída má úložiště pro položky zobrazení tabulky a přepíše GetRowCount počet řádků v tabulce.

Nakonec musíme vytvořit podtřídu, která NSTableDelegate zajistí chování naší tabulky. V Průzkumník řešení klikněte pravým tlačítkem na Projekt a vyberte Přidat>nový soubor... Vyberte Obecné>prázdné třídy, zadejte ProductTableDelegate název a klikněte na tlačítko Nový.

ProductTableDelegate.cs Upravte soubor a udělejte ho takto:

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

Když vytvoříme instanci objektu ProductTableDelegate, předáme také instanci ProductTableDataSource , která poskytuje data pro tabulku. Metoda GetViewForItem zodpovídá za vrácení zobrazení (dat) pro zobrazení buňky pro sloupec a řádek. Pokud je to možné, existující zobrazení bude znovu použito k zobrazení buňky, pokud není nové zobrazení nutné vytvořit.

Pokud chcete naplnit tabulku, pojďme soubor upravit ViewController.cs a nastavit, aby AwakeFromNib metoda vypadala takto:

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

Pokud spustíme aplikaci, zobrazí se následující:

Screenshot shows a window named Product Table with three entries.

Řazení podle sloupce

Umožníme uživateli seřadit data v tabulce kliknutím na záhlaví sloupce. Nejprve poklikáním na Main.storyboard soubor otevřete soubor pro úpravy v Tvůrci rozhraní. Product Vyberte sloupec, zadejte Title klíč řazení, compare: pro selektor a vyberte Ascendingpořadí:

Screenshot shows the Interface Builder where you can set the sort key for the Product column.

Details Vyberte sloupec, zadejte Description klíč řazení, compare: pro selektor a vyberte Ascendingpořadí:

Screenshot shows the Interface Builder where you can set the sort key for the Details column.

Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Teď soubor upravíme ProductTableDataSource.cs a přidáme následující metody:

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

Metoda Sort nám umožňuje seřadit data ve zdroji dat na základě daného Product pole třídy ve vzestupném nebo sestupném pořadí. Přepsaná SortDescriptorsChanged metoda bude volána při každém kliknutí na záhlaví sloupce. Předá se hodnota Klíče , kterou jsme nastavili v Tvůrci rozhraní, a pořadí řazení pro daný sloupec.

Pokud spustíme aplikaci a klikneme na záhlaví sloupců, řádky se seřadí podle daného sloupce:

An example app run

Výběr řádku

Pokud chcete uživateli povolit výběr jednoho řádku, poklikejte na soubor a otevřete ho Main.storyboard pro úpravy v Tvůrci rozhraní. Vyberte zobrazení tabulky v hierarchii rozhraní a zrušte zaškrtnutí políčka Více v inspektoru atributů:

Screenshot shows the Interface Builder where you can select Multiple in the Attribute Inspector.

Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Dále upravte ProductTableDelegate.cs soubor a přidejte následující metodu:

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

To uživateli umožní vybrat libovolný jeden řádek v zobrazení tabulky. Vraťte false se ShouldSelectRow pro libovolný řádek, který nechcete, aby uživatel mohl vybrat nebo false pro každý řádek, pokud nechcete, aby uživatel mohl vybrat žádné řádky.

Zobrazení tabulky (NSTableView) obsahuje následující metody pro práci s výběrem řádku:

  • DeselectRow(nint) – Zruší výběr daného řádku v tabulce.
  • SelectRow(nint,bool) - Vybere daný řádek. Předání false druhého parametru pro výběr pouze jednoho řádku najednou.
  • SelectedRow – Vrátí aktuální řádek vybraný v tabulce.
  • IsRowSelected(nint) - Vrátí true , pokud je vybraný daný řádek.

Výběr více řádků

Pokud chcete uživateli povolit výběr více řádků, poklikáním Main.storyboard otevřete soubor pro úpravy v Tvůrci rozhraní. Vyberte zobrazení tabulky v hierarchii rozhraní a zaškrtněte políčko Více v inspektoru atributů:

Screenshot shows the Interface Builder where you can select Multiple to allow multiple row selection.

Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Dále upravte ProductTableDelegate.cs soubor a přidejte následující metodu:

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

To uživateli umožní vybrat libovolný jeden řádek v zobrazení tabulky. Vraťte false se ShouldSelectRow pro libovolný řádek, který nechcete, aby uživatel mohl vybrat nebo false pro každý řádek, pokud nechcete, aby uživatel mohl vybrat žádné řádky.

Zobrazení tabulky (NSTableView) obsahuje následující metody pro práci s výběrem řádku:

  • DeselectAll(NSObject) – Zruší výběr všech řádků v tabulce. Slouží this k odeslání prvního parametru v objektu, který provádí výběr.
  • DeselectRow(nint) – Zruší výběr daného řádku v tabulce.
  • SelectAll(NSobject) – Vybere všechny řádky v tabulce. Slouží this k odeslání prvního parametru v objektu, který provádí výběr.
  • SelectRow(nint,bool) - Vybere daný řádek. Předání druhého parametru vymaže výběr a vybere jenom jeden řádek, předáte falsetrue ho a rozšíříte výběr a zahrnete tento řádek.
  • SelectRows(NSIndexSet,bool) - Vybere danou sadu řádků. Předání druhého parametru vymaže výběr a vybere jenom tyto řádky, předá false se true pro rozšíření výběru a zahrnutí těchto řádků.
  • SelectedRow – Vrátí aktuální řádek vybraný v tabulce.
  • SelectedRows – Vrátí NSIndexSet indexy vybraných řádků.
  • SelectedRowCount – Vrátí počet vybraných řádků.
  • IsRowSelected(nint) - Vrátí true , pokud je vybraný daný řádek.

Typ pro výběr řádku

Pokud chcete uživateli povolit zadání znaku s vybraným zobrazením tabulky a výběrem prvního řádku s tímto znakem, poklikejte na Main.storyboard soubor a otevřete ho pro úpravy v Tvůrci rozhraní. Vyberte zobrazení tabulky v hierarchii rozhraní a zaškrtněte políčko Vybrat typ v inspektoru atributů:

Setting the selection type

Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Teď soubor upravíme ProductTableDelegate.cs a přidáme následující metodu:

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

Metoda GetNextTypeSelectMatch vezme danou searchString a vrátí řádek prvníhoProduct, který má tento řetězec v něm .Title

Pokud spustíme aplikaci a zadáme znak, vybere se řádek:

Screenshot shows the result of running the application.

Změna pořadí sloupců

Pokud chcete uživateli povolit přeuspořádání sloupců v zobrazení tabulky, poklikejte na soubor a otevřete ho Main.storyboard pro úpravy v Tvůrci rozhraní. Vyberte zobrazení tabulky v hierarchii rozhraní a zaškrtněte políčko Změnit pořadí v inspektoru atributů:

Screenshot shows the Interface Builder where you can select Reodering in the Attribute Inspector.

Pokud zadáme hodnotu vlastnosti Automatické ukládání a zkontrolujeme pole Informace o sloupci, všechny změny provedené v rozložení tabulky se automaticky uloží za nás a obnoví se při příštím spuštění aplikace.

Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Teď soubor upravíme ProductTableDelegate.cs a přidáme následující metodu:

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

Metoda ShouldReorder by měla vrátit true pro libovolný sloupec, který chcete povolit přetáhnout do newColumnIndex, jinak vrátit false;

Pokud spustíme aplikaci, můžeme záhlaví sloupců přetáhnout kolem a změnit pořadí sloupců:

An example of the reordered columns

Úpravy buněk

Pokud chcete uživateli povolit úpravy hodnot pro danou buňku, upravte ProductTableDelegate.cs soubor a změňte metodu GetViewForItem následujícím způsobem:

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

Když teď spustíme aplikaci, uživatel může upravit buňky v zobrazení tabulky:

An example of editing a cell

Použití obrázků v zobrazeních tabulek

Pokud chcete do buňky zahrnout obrázek jako NSTableViewsoučást buňky, budete muset změnit způsob, jakým jsou data vrácena metodou ZobrazeníGetViewForItemNSTableViewDelegate'stabulky, aby místo NSTableCellView typického NSTextField. Příklad:

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

Další informace najdete v části Použití obrázků se zobrazeními tabulek v naší dokumentaci Práce s obrázky .

Přidání tlačítka Odstranit na řádek

V závislosti na požadavcích aplikace můžou nastat situace, kdy potřebujete zadat tlačítko akce pro každý řádek v tabulce. V příkladu tohoto příkladu rozbalme výše vytvořený příklad zobrazení tabulky, abychom na každém řádku zahrnuli tlačítko Odstranit .

Nejprve upravte Main.storyboard Tvůrce rozhraní Xcode, vyberte zobrazení tabulky a zvyšte počet sloupců na tři (3). Dále změňte název nového sloupce na Action:

Editing the column name

Uložte změny do scénáře a vraťte se do Visual Studio pro Mac, aby se změny synchronizovaly.

Dále upravte ViewController.cs soubor a přidejte následující veřejnou metodu:

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

Ve stejném souboru upravte vytvoření nového delegáta zobrazení tabulky uvnitř ViewDidLoad metody následujícím způsobem:

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

Teď upravte ProductTableDelegate.cs soubor tak, aby zahrnoval privátní připojení k řadiči zobrazení a při vytváření nové instance delegáta převezměte kontroler jako parametr:

#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

Dále do třídy přidejte následující novou privátní metodu:

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

To přebírá všechny konfigurace textového zobrazení, které byly provedeny v GetViewForItem metodě a umístí je do jediného volatelného umístění (od posledního sloupce tabulky neobsahuje textové zobrazení, ale tlačítko).

Nakonec upravte metodu GetViewForItem a nastavte ji jako následující:

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

Pojďme se podrobněji podívat na několik částí tohoto kódu. Nejprve se provede nová NSTableViewCell akce na základě názvu sloupce. Pro první dva sloupce (Product a Details) se volá nová ConfigureTextField metoda.

Pro sloupec Akce se vytvoří nový NSButton a přidá se do buňky jako dílčí zobrazení:

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

Vlastnost Button Tag slouží k uložení počtu zpracovávaných řádků. Toto číslo se použije později, když uživatel požádá o odstranění řádku v události tlačítka Activated :

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

Na začátku obslužné rutiny události získáme tlačítko a produkt, který je na daném řádku tabulky. Uživateli, který potvrdí odstranění řádku, se zobrazí výstraha. Pokud se uživatel rozhodne řádek odstranit, daný řádek se odebere ze zdroje dat a tabulka se znovu načte:

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

A konečně, pokud se buňka zobrazení tabulky místo vytváření nových znovu používá, nakonfiguruje ji následující kód na základě zpracovávaného sloupce:

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

U sloupce Akce jsou všechna dílčí zobrazení prohledávána, dokud NSButton se nenajde, a pak se Tag vlastnost aktualizuje tak, aby ukazovala na aktuální řádek.

Po provedení těchto změn bude mít aplikace při každém spuštění každého řádku tlačítko Odstranit :

The table view with deletion buttons

Když uživatel klikne na tlačítko Odstranit , zobrazí se upozornění s žádostí o odstranění daného řádku:

A delete row alert

Pokud uživatel zvolí odstranění, řádek se odebere a tabulka se překreslí:

The table after the row is deleted

Zobrazení tabulky datových vazeb

Pomocí technik kódování klíč-hodnota a datové vazby v aplikaci Xamarin.Mac můžete výrazně snížit množství kódu, který musíte napsat a udržovat pro naplnění a práci s prvky uživatelského rozhraní. Výhodou je také další oddělení backingových dat (datový model) od front-endového uživatelského rozhraní (Model-View-Controller), což usnadňuje údržbu a flexibilnější návrh aplikace.

Kódování klíč-hodnota (KVC) je mechanismus pro přístup k vlastnostem objektu nepřímo pomocí klíčů (speciálně formátovaných řetězců) k identifikaci vlastností místo přístupu prostřednictvím proměnných instancí nebo metod přístupového objektu (get/set). Implementací přístupových objektů kompatibilních s kódováním klíč-hodnota v aplikaci Xamarin.Mac získáte přístup k dalším funkcím systému macOS, jako je KVO (Key-Value Observing), Datová vazba, Základní data, vazby Cocoa a skriptovatelnost.

Další informace najdete v části Datové vazby zobrazení tabulky v dokumentaci k datovým vazbě a kódování klíč-hodnota.

Shrnutí

Tento článek se podrobně podíval na práci se zobrazeními tabulek v aplikaci Xamarin.Mac. Viděli jsme různé typy a použití zobrazení tabulek, jak vytvářet a udržovat zobrazení tabulky v Tvůrci rozhraní Xcode a jak pracovat se zobrazeními tabulek v kódu jazyka C#.