Udostępnij za pośrednictwem


Widoki tabel na platformie Xamarin.Mac

W tym artykule opisano pracę z widokami tabel w aplikacji platformy Xamarin.Mac. W tym artykule opisano tworzenie widoków tabel w środowisku Xcode i narzędziu Interface Builder oraz interakcję z nimi w kodzie.

Podczas pracy z językiem C# i platformą .NET w aplikacji platformy Xamarin.Mac masz dostęp do tych samych widoków tabeli, w Objective-C których pracuje deweloper i czy program Xcode . Ponieważ platforma Xamarin.Mac integruje się bezpośrednio z programem Xcode, możesz użyć narzędzia Xcode Interface Builder do tworzenia i obsługi widoków tabel (lub opcjonalnie tworzenia ich bezpośrednio w kodzie języka C#).

Widok tabeli wyświetla dane w formacie tabelarycznym zawierającym co najmniej jedną kolumnę informacji w wielu wierszach. Na podstawie typu tworzonego widoku tabeli użytkownik może sortować według kolumn, reorganizować kolumny, dodawać kolumny, usuwać kolumny lub edytować dane zawarte w tabeli.

Przykładowa tabela

W tym artykule omówimy podstawy pracy z widokami tabel w aplikacji platformy Xamarin.Mac. Zdecydowanie zaleca się, aby najpierw zapoznać się z artykułem Hello, Mac , w szczególności wprowadzenie do narzędzi Xcode i Interface Builder i Outlet and Actions , ponieważ obejmuje ona kluczowe pojęcia i techniki, których będziemy używać w tym artykule.

Warto zapoznać się również z sekcją Uwidacznianie klas/ metod Objective-C języka C# w dokumencie Xamarin.Mac Internals . Register Objaśnienie poleceń i Export używanych do podłączania klas języka C# do Objective-C obiektów i elementów interfejsu użytkownika.

Wprowadzenie do widoków tabel

Widok tabeli wyświetla dane w formacie tabelarycznym zawierającym co najmniej jedną kolumnę informacji w wielu wierszach. Widoki tabeli są wyświetlane wewnątrz widoków przewijania () iNSScrollView począwszy od systemu macOS 10.7, można użyć dowolnego NSView zamiast komórek (NSCell), aby wyświetlić zarówno wiersze, jak i kolumny. Mimo to nadal można użyć NSCell klasy podrzędnej NSTableCellView i utworzyć niestandardowe wiersze i kolumny.

Widok tabeli nie przechowuje własnych danych, zamiast tego opiera się na źródle danych (NSTableViewDataSource), aby zapewnić wymagane zarówno wiersze, jak i kolumny zgodnie z potrzebami.

Zachowanie widoku tabeli można dostosować, udostępniając podklasę delegata widoku tabel (NSTableViewDelegate) w celu obsługi zarządzania kolumnami tabel, typu w celu wybrania funkcji, zaznaczenia i edytowania wierszy, śledzenia niestandardowego i widoków niestandardowych dla poszczególnych kolumn i wierszy.

Podczas tworzenia widoków tabel firma Apple sugeruje następujące kwestie:

  • Zezwalaj użytkownikowi na sortowanie tabeli, klikając nagłówki kolumn.
  • Utwórz nagłówki kolumn, które są nounami lub krótkimi frazami unun, które opisują dane wyświetlane w tej kolumnie.

Aby uzyskać więcej informacji, zobacz sekcję Content Views (Widoki zawartości) w wytycznych dotyczących interfejsu użytkownika systemu OS X firmy Apple.

Tworzenie i obsługa widoków tabel w programie Xcode

Podczas tworzenia nowej aplikacji platformy Xamarin.Mac Cocoa domyślnie zostanie wyświetlone standardowe puste okno. Te okna są definiowane w pliku automatycznie dołączonym .storyboard do projektu. Aby edytować projekt systemu Windows, w Eksplorator rozwiązań kliknij Main.storyboard dwukrotnie plik:

Wybieranie głównego scenorysu

Spowoduje to otwarcie projektu okna w narzędziu Interface Builder programu Xcode:

Edytowanie interfejsu użytkownika w środowisku Xcode

Wpisz table w polu wyszukiwania Inspektora biblioteki, aby ułatwić znajdowanie kontrolek Widok tabeli:

Wybieranie widoku tabeli z biblioteki

Przeciągnij widok tabeli na kontroler widoku w Edytorze interfejsów, wypełnij obszar zawartości kontrolera widoku i ustaw go na miejsce, w którym zmniejsza się i rośnie wraz z oknem w Edytorze ograniczeń:

Edytowanie ograniczeń

Wybierz widok tabeli w hierarchii interfejsu, a następujące właściwości są dostępne w Inspektorze atrybutów:

Zrzut ekranu przedstawia właściwości dostępne w Inspektorze atrybutów.

  • Tryb zawartości — umożliwia wyświetlanie danych w wierszach i kolumnach przy użyciu widoków (NSView) lub komórek (NSCell). Począwszy od systemu macOS 10.7, należy użyć widoków.
  • Liczba zmiennoprzecinkowa Grupuj wiersze — jeśli truewidok tabeli będzie rysować pogrupowane komórki tak, jakby były przestawne.
  • Kolumny — definiuje liczbę wyświetlanych kolumn.
  • Nagłówki — jeśli truekolumny będą miały nagłówki.
  • Zmiana kolejności — jeśli trueużytkownik będzie mógł przeciągnąć kolejność kolumn w tabeli.
  • Zmiana rozmiaru — jeśli trueużytkownik będzie mógł przeciągać nagłówki kolumn w celu zmiany rozmiaru kolumn.
  • Ustalanie rozmiaru kolumn — określa sposób automatycznego rozmiaru kolumn tabeli.
  • Wyróżnienie — określa typ wyróżniania tabeli, który jest używany podczas wybierania komórki.
  • Alternatywne wiersze — jeśli truekiedykolwiek inny wiersz będzie miał inny kolor tła.
  • Siatka pozioma — wybiera typ obramowania rysowanego między komórkami poziomo.
  • Siatka pionowa — wybiera typ obramowania rysowanego między komórkami w pionie.
  • Kolor siatki — ustawia kolor obramowania komórki.
  • Tło — ustawia kolor tła komórki.
  • Wybór — umożliwia kontrolowanie sposobu wybierania komórek w tabeli przez użytkownika jako:
    • Wiele — jeśli trueużytkownik może wybrać wiele wierszy i kolumn.
    • Kolumna — jeśli trueużytkownik może wybrać kolumny.
    • Typ Wybierz — jeśli trueużytkownik może wpisać znak, aby wybrać wiersz.
    • Puste — jeśli trueużytkownik nie jest wymagany do wybrania wiersza lub kolumny, tabela w ogóle nie zezwala na wybór.
  • Autozapis — nazwa, w ramach którego format tabel jest zapisywany automatycznie.
  • Informacje o kolumnie — jeśli truekolejność i szerokość kolumn zostaną automatycznie zapisane.
  • Podziały wierszy — wybierz sposób obsługi podziałów wierszy przez komórkę.
  • Obcina ostatnią widoczną linię — jeśli truekomórka zostanie obcięta w danych, nie mieści się w granicach.

Ważne

Jeśli nie utrzymujesz starszej aplikacji platformy Xamarin.Mac, NSView widoki tabel na podstawie powinny być używane w NSCell widokach tabel opartych. NSCell jest uważana za starszą i może nie być obsługiwana w przyszłości.

Wybierz kolumnę tabeli w hierarchii interfejsu, a w Inspektorze atrybutów są dostępne następujące właściwości:

Zrzut ekranu przedstawia właściwości dostępne dla kolumny tabeli w Inspektorze atrybutów.

  • Title — ustawia tytuł kolumny.
  • Wyrównanie — ustawianie wyrównania tekstu w komórkach.
  • Czcionka tytułu — wybiera czcionkę dla tekstu nagłówka komórki.
  • Klucz sortowania — jest kluczem używanym do sortowania danych w kolumnie. Pozostaw pole puste, jeśli użytkownik nie może posortować tej kolumny.
  • Selektor — czy akcja służy do sortowania. Pozostaw pole puste, jeśli użytkownik nie może posortować tej kolumny.
  • Order — to kolejność sortowania danych kolumn.
  • Zmiana rozmiaru — wybiera typ zmiany rozmiaru kolumny.
  • Edytowalne — jeśli trueużytkownik może edytować komórki w tabeli opartej na komórkach.
  • Ukryte — jeśli truekolumna jest ukryta.

Możesz również zmienić rozmiar kolumny, przeciągając uchwyt (w pionie wyśrodkowany po prawej stronie kolumny) w lewo lub w prawo.

Wybierzmy każdą kolumnę w widoku tabeli i nadajmy pierwszej kolumnie tytuł Product i drugą Detailskolumnę .

Wybierz widok komórki tabeli (NSTableViewCell) w hierarchii interfejsu i następujące właściwości są dostępne w Inspektorze atrybutów:

Zrzut ekranu przedstawia właściwości dostępne dla widoku komórki tabeli w Inspektorze atrybutów.

Są to wszystkie właściwości widoku standardowego. Istnieje również możliwość zmiany rozmiaru wierszy dla tej kolumny tutaj.

Wybierz komórkę widoku tabeli (domyślnie jest NSTextFieldto ) w hierarchii interfejsu, a następujące właściwości są dostępne w Inspektorze atrybutów:

Zrzut ekranu przedstawia właściwości dostępne dla komórki widoku tabeli w Inspektorze atrybutów.

Wszystkie właściwości standardowego pola tekstowego zostaną ustawione tutaj. Domyślnie standardowe pole tekstowe służy do wyświetlania danych dla komórki w kolumnie.

Wybierz widok komórki tabeli (NSTableFieldCell) w hierarchii interfejsu i następujące właściwości są dostępne w Inspektorze atrybutów:

Zrzut ekranu przedstawia właściwości dostępne dla innej komórki widoku tabeli w Inspektorze atrybutów.

Najważniejsze ustawienia są następujące:

  • Układ — wybierz sposób, w jaki komórki w tej kolumnie są ułożone.
  • Używa trybu pojedynczego wiersza — jeśli truekomórka jest ograniczona do pojedynczego wiersza.
  • Pierwsza szerokość układu środowiska uruchomieniowego — jeśli truekomórka będzie preferować ustawioną szerokość (ręcznie lub automatycznie), gdy jest wyświetlana po pierwszym uruchomieniu aplikacji.
  • Akcja — określa, kiedy akcja edycji jest wysyłana dla komórki.
  • Zachowanie — określa, czy komórka jest wybierana lub edytowalna.
  • Tekst sformatowany — jeśli truekomórka może wyświetlać sformatowany i stylizowany tekst.
  • Cofnij — jeśli truekomórka przejmuje odpowiedzialność za jego zachowanie cofania.

Wybierz widok komórki tabeli (NSTableFieldCell) w dolnej części kolumny tabeli w hierarchii interfejsu:

Wybieranie widoku komórki tabeli

Dzięki temu można edytować widok komórek tabeli używany jako podstawowy wzorzec dla wszystkich komórek utworzonych dla danej kolumny.

Dodawanie akcji i gniazd

Podobnie jak w przypadku każdej innej kontrolki interfejsu użytkownika cocoa, musimy uwidocznić widok tabeli i kolumny oraz komórki w kodzie języka C# przy użyciu akcji i punktów ( na podstawie wymaganych funkcji).

Proces jest taki sam dla każdego elementu Widoku tabeli, który chcemy uwidocznić:

  1. Przejdź do Edytora asystentów i upewnij się, że ViewController.h plik został wybrany:

    Edytor asystenta

  2. Wybierz widok tabeli z hierarchii interfejsu, kliknij i przeciągnij do ViewController.h pliku.

  3. Utwórz gniazdo dla widoku tabeli o nazwie ProductTable:

    Zrzut ekranu przedstawiający połączenie gniazdka utworzone dla widoku tabeli o nazwie ProductTable.

  4. Utwórz punkty dla kolumn tabel, a także o nazwie ProductColumn i DetailsColumn:

    Zrzut ekranu przedstawia połączenia wylotowe utworzone dla innych widoków tabeli.

  5. Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Następnie napiszemy kod wyświetlając dane dla tabeli po uruchomieniu aplikacji.

Wypełnianie widoku tabeli

W naszym widoku tabeli zaprojektowanym w narzędziu Interface Builder i uwidocznieniu za pośrednictwem gniazda należy utworzyć kod języka C#, aby go wypełnić.

Najpierw utwórzmy nową Product klasę do przechowywania informacji dla poszczególnych wierszy. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy plik... Wybierz pozycję Ogólna>Pusta klasa, wprowadź Product nazwę i kliknij przycisk Nowy:

Tworzenie pustej klasy

Product.cs Utwórz plik w następujący sposób:

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

Następnie musimy utworzyć podklasę, aby podać dane dla naszej tabeli zgodnie z NSTableDataSource żądaniem. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy plik... Wybierz pozycję Ogólna>Pusta klasa, wprowadź ProductTableDataSource nazwę i kliknij przycisk Nowy.

Zmodyfikuj ProductTableDataSource.cs plik i utwórz go w następujący sposób:

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

Ta klasa zawiera magazyn elementów widoku tabeli i zastępuje GetRowCount element , aby zwrócić liczbę wierszy w tabeli.

Na koniec musimy utworzyć podklasę NSTableDelegate , aby zapewnić zachowanie naszej tabeli. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy plik... Wybierz pozycję Ogólna>Pusta klasa, wprowadź ProductTableDelegate nazwę i kliknij przycisk Nowy.

Zmodyfikuj ProductTableDelegate.cs plik i utwórz go w następujący sposób:

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

Podczas tworzenia wystąpienia klasy przekazujemy również wystąpienie ProductTableDelegateProductTableDataSource obiektu , które dostarcza dane dla tabeli. Metoda GetViewForItem jest odpowiedzialna za zwracanie widoku (danych) w celu wyświetlenia komórki dla kolumny i wiersza. Jeśli to możliwe, istniejący widok zostanie ponownie użyty do wyświetlenia komórki, jeśli nie zostanie utworzony nowy widok.

Aby wypełnić tabelę, edytujmy ViewController.cs plik i utwórzmy metodę AwakeFromNib podobną do następującej:

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

Jeśli uruchomimy aplikację, zostanie wyświetlona następująca wartość:

Zrzut ekranu przedstawia okno o nazwie Tabela produktów z trzema wpisami.

Sortowanie według kolumny

Zezwólmy użytkownikowi na sortowanie danych w tabeli, klikając nagłówek kolumny. Najpierw kliknij dwukrotnie plik, aby otworzyć go do edycji w narzędziu Main.storyboard Interface Builder. Wybierz kolumnęProduct, wprowadź dla Title pola Sort Key ( compare: Klucz sortowania) dla selektora i wybierz pozycję Ascending Order (Kolejność):

Zrzut ekranu przedstawia konstruktora interfejsu, w którym można ustawić klucz sortowania dla kolumny Product.

Wybierz kolumnęDetails, wprowadź dla Description pola Sort Key ( compare: Klucz sortowania) dla selektora i wybierz pozycję Ascending Order (Kolejność):

Zrzut ekranu przedstawia konstruktora interfejsu, w którym można ustawić klucz sortowania dla kolumny Szczegóły.

Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Teraz edytujemy ProductTableDataSource.cs plik i dodajmy następujące 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 umożliwia sortowanie danych w źródle danych na podstawie danego Product pola klasy w kolejności rosnącej lub malejącej. Przesłonięta SortDescriptorsChanged metoda będzie wywoływana za każdym razem, gdy użycie kliknie nagłówek kolumny. Zostanie przekazana wartość Klucz ustawiona w narzędziu Interface Builder i kolejność sortowania dla tej kolumny.

Jeśli uruchomimy aplikację i klikniemy w nagłówkach kolumn, wiersze zostaną posortowane według tej kolumny:

Uruchamianie przykładowej aplikacji

Wybór wiersza

Jeśli chcesz zezwolić użytkownikowi na wybranie jednego wiersza, kliknij Main.storyboard dwukrotnie plik, aby otworzyć go do edycji w narzędziu Interface Builder. Wybierz widok tabeli w hierarchii interfejsu i usuń zaznaczenie pola wyboru Wiele w inspektorze atrybutów:

Zrzut ekranu przedstawia konstruktora interfejsu, w którym można wybrać pozycję Wiele w Inspektorze atrybutów.

Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Następnie zmodyfikuj ProductTableDelegate.cs plik i dodaj następującą metodę:

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

Pozwoli to użytkownikowi wybrać dowolny pojedynczy wiersz w widoku tabeli. Zwróć false wartość dla ShouldSelectRow dowolnego wiersza, którego nie chcesz, aby użytkownik mógł wybrać lub false dla każdego wiersza, jeśli nie chcesz, aby użytkownik mógł wybrać jakiekolwiek wiersze.

Widok tabeli (NSTableView) zawiera następujące metody pracy z wyborem wierszy:

  • DeselectRow(nint) — Usuwa zaznaczenie danego wiersza w tabeli.
  • SelectRow(nint,bool) - Wybiera dany wiersz. Przekaż false drugi parametr, aby wybrać tylko jeden wiersz jednocześnie.
  • SelectedRow — Zwraca bieżący wiersz wybrany w tabeli.
  • IsRowSelected(nint) — Zwraca true wartość, jeśli dany wiersz jest zaznaczony.

Wybór wielu wierszy

Jeśli chcesz zezwolić użytkownikowi na wybranie wielu wierszy, kliknij Main.storyboard dwukrotnie plik, aby otworzyć go do edycji w narzędziu Interface Builder. Wybierz widok tabeli w hierarchii interfejsu i zaznacz pole wyboru Wiele w Inspektorze atrybutów:

Zrzut ekranu przedstawia konstruktora interfejsu, w którym można wybrać pozycję Wiele, aby zezwolić na wybór wielu wierszy.

Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Następnie zmodyfikuj ProductTableDelegate.cs plik i dodaj następującą metodę:

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

Pozwoli to użytkownikowi wybrać dowolny pojedynczy wiersz w widoku tabeli. Zwróć false wartość dla ShouldSelectRow dowolnego wiersza, którego nie chcesz, aby użytkownik mógł wybrać lub false dla każdego wiersza, jeśli nie chcesz, aby użytkownik mógł wybrać jakiekolwiek wiersze.

Widok tabeli (NSTableView) zawiera następujące metody pracy z wyborem wierszy:

  • DeselectAll(NSObject) — Usuwa zaznaczenie wszystkich wierszy w tabeli. Użyj this dla pierwszego parametru do wysłania w obiekcie wykonującym zaznaczenie.
  • DeselectRow(nint) — Usuwa zaznaczenie danego wiersza w tabeli.
  • SelectAll(NSobject) — Wybiera wszystkie wiersze w tabeli. Użyj this dla pierwszego parametru do wysłania w obiekcie wykonującym zaznaczenie.
  • SelectRow(nint,bool) - Wybiera dany wiersz. Przekaż false drugi parametr, aby wyczyścić zaznaczenie i wybrać tylko jeden wiersz, przekazać true , aby rozszerzyć zaznaczenie i dołączyć ten wiersz.
  • SelectRows(NSIndexSet,bool) - Wybiera dany zestaw wierszy. Przekaż false drugi parametr, aby wyczyścić zaznaczenie i wybrać tylko te wiersze, przekazać true polecenie w celu rozszerzenia zaznaczenia i dołączyć te wiersze.
  • SelectedRow — Zwraca bieżący wiersz wybrany w tabeli.
  • SelectedRows — Zwraca NSIndexSet indeksy wybranych wierszy.
  • SelectedRowCount — Zwraca liczbę wybranych wierszy.
  • IsRowSelected(nint) — Zwraca true wartość, jeśli dany wiersz jest zaznaczony.

Wpisz, aby wybrać wiersz

Jeśli chcesz zezwolić użytkownikowi na wpisywanie znaku przy użyciu wybranego widoku tabeli i zaznacz pierwszy wiersz, który ma ten znak, kliknij Main.storyboard dwukrotnie plik, aby otworzyć go do edycji w narzędziu Interface Builder. Wybierz widok tabeli w hierarchii interfejsu i zaznacz pole wyboru Typ Zaznacz w Inspektorze atrybutów:

Ustawianie typu wyboru

Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Teraz edytujemy ProductTableDelegate.cs plik i dodajmy następującą metodę:

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 przyjmuje daną searchString wartość i zwraca wiersz pierwszego Product , który zawiera ten ciąg w elemecie Title.

Jeśli uruchomimy aplikację i wpiszemy znak, zostanie wybrany wiersz:

Zrzut ekranu przedstawia wynik uruchomienia aplikacji.

Zmienianie kolejności kolumn

Jeśli chcesz zezwolić użytkownikowi na przeciąganie kolumn zmiany kolejności w widoku tabeli, kliknij Main.storyboard dwukrotnie plik, aby otworzyć go do edycji w narzędziu Interface Builder. Zaznacz widok tabeli w hierarchii interfejsu i zaznacz pole wyboru Zmień kolejność w Inspektorze atrybutów:

Zrzut ekranu przedstawia konstruktora interfejsu, w którym można wybrać pozycję Ponowne łączenie w Inspektorze atrybutów.

Jeśli nadasz wartość właściwości Autosave i sprawdzimy pole Informacje o kolumnie, wszelkie zmiany wprowadzone w układzie tabeli zostaną automatycznie zapisane i przywrócone przy następnym uruchomieniu aplikacji.

Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.

Teraz edytujemy ProductTableDelegate.cs plik i dodajmy następującą metodę:

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

Metoda ShouldReorder powinna zwracać true dowolną kolumnę, którą chce zezwolić na przeciąganie zmiany kolejności do newColumnIndexelementu , w przeciwnym razie zwróć wartość false;

Jeśli uruchomimy aplikację, możemy przeciągnąć nagłówki kolumn, aby zmienić kolejność kolumn:

Przykład przesuniętych kolumn

Edytowanie komórek

Jeśli chcesz zezwolić użytkownikowi na edytowanie wartości dla danej komórki, zmodyfikuj ProductTableDelegate.cs plik i zmień metodę GetViewForItem w następujący sposób:

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

Teraz, jeśli uruchomimy aplikację, użytkownik może edytować komórki w widoku tabeli:

Przykład edytowania komórki

Używanie obrazów w widokach tabeli

Aby dołączyć obraz jako część komórki w NSTableViewobiekcie , należy zmienić sposób zwracania danych przez metodę Widoku GetViewForItem NSTableViewDelegate's tabeli, aby użyć NSTableCellView elementu zamiast typowego NSTextFieldelementu . Na przykład:

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

Aby uzyskać więcej informacji, zobacz sekcję Using Images with Table Views (Używanie obrazów z widokami tabel) w dokumentacji dotyczącej pracy z obrazem .

Dodawanie przycisku Usuwania do wiersza

Na podstawie wymagań aplikacji mogą wystąpić sytuacje, w których trzeba podać przycisk akcji dla każdego wiersza w tabeli. W tym przykładzie rozwińmy powyższy przykład widoku tabeli, aby uwzględnić przycisk Usuń w każdym wierszu.

Najpierw zmodyfikuj element w narzędziu Main.storyboard Interface Builder programu Xcode, wybierz widok tabeli i zwiększ liczbę kolumn do trzech (3). Następnie zmień tytuł nowej kolumny na Action:

Edytowanie nazwy kolumny

Zapisz zmiany w scenorysie i wróć do Visual Studio dla komputerów Mac, aby zsynchronizować zmiany.

Następnie zmodyfikuj ViewController.cs plik i dodaj następującą metodę publiczną:

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

W tym samym pliku zmodyfikuj tworzenie nowego delegata widoku tabeli wewnątrz ViewDidLoad metody w następujący sposób:

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

Teraz zmodyfikuj ProductTableDelegate.cs plik, aby uwzględnić połączenie prywatne z kontrolerem widoku i przejąć kontroler jako parametr podczas tworzenia nowego wystąpienia delegata:

#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

Następnie dodaj następującą nową metodę prywatną do klasy:

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

Przyjmuje to wszystkie konfiguracje widoku tekstu, które były wcześniej wykonywane w GetViewForItem metodzie i umieszcza je w jednej, wywoływanej lokalizacji (ponieważ ostatnia kolumna tabeli nie zawiera widoku tekstu, ale przycisku).

Na koniec zmodyfikuj metodę GetViewForItem i ustaw ją tak:

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

Przyjrzyjmy się kilku sekcjom tego kodu bardziej szczegółowo. Najpierw, jeśli tworzona jest nowa NSTableViewCell akcja jest podejmowana na podstawie nazwy kolumny. Dla dwóch pierwszych kolumn (Product i Details) nowa metoda jest wywoływana ConfigureTextField .

W kolumnie Akcja zostanie utworzona nowa NSButton i dodana do komórki jako widok podrzędny:

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

Właściwość Przycisku Tag służy do przechowywania liczby aktualnie przetwarzanych wierszy. Ten numer będzie używany później, gdy użytkownik zażąda usunięcia wiersza w zdarzeniu przycisku 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 początku procedury obsługi zdarzeń otrzymujemy przycisk i produkt znajdujący się w danym wierszu tabeli. Następnie zostanie wyświetlony alert dla użytkownika potwierdzającego usunięcie wiersza. Jeśli użytkownik zdecyduje się usunąć wiersz, dany wiersz zostanie usunięty ze źródła danych, a tabela zostanie ponownie załadowana:

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

Na koniec, jeśli komórka widoku tabeli jest ponownie wykorzystywana zamiast tworzyć nowe, następujący kod konfiguruje go na podstawie przetwarzanej kolumny:

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

W kolumnie Akcja wszystkie widoki podrzędne są skanowane do momentu NSButton znalezienia, a następnie właściwość Tag jest aktualizowana tak, aby wskazywała bieżący wiersz.

Po wprowadzeniu tych zmian po uruchomieniu aplikacji każdy wiersz będzie miał przycisk Usuń :

Widok tabeli z przyciskami usuwania

Gdy użytkownik kliknie przycisk Usuń , zostanie wyświetlony alert z prośbą o usunięcie danego wiersza:

Alert dotyczący usuwania wiersza

Jeśli użytkownik wybierze opcję usunięcia, wiersz zostanie usunięty, a tabela zostanie ponownie wyrysowana:

Tabela po usunięciu wiersza

Widoki tabel powiązań danych

Korzystając z technik kodowania klucz-wartość i powiązania danych w aplikacji Xamarin.Mac, można znacznie zmniejszyć ilość kodu, który trzeba napisać i obsługiwać, aby wypełnić elementy interfejsu użytkownika i pracować z elementami interfejsu użytkownika. Masz również korzyść z dalszego oddzielenia danych zapasowych (modelu danych) od interfejsu użytkownika frontonu (Model-View-Controller), co prowadzi do łatwiejszego utrzymania, bardziej elastycznego projektowania aplikacji.

Kodowanie klucz-wartość (KVC) jest mechanizmem uzyskiwania dostępu do właściwości obiektu pośrednio przy użyciu kluczy (specjalnie sformatowanych ciągów) do identyfikowania właściwości zamiast uzyskiwania do nich dostępu za pośrednictwem zmiennych wystąpienia lub metod metod dostępu (get/set). Implementując metody dostępu zgodne z kodowaniem klucz-wartość w aplikacji Xamarin.Mac, uzyskujesz dostęp do innych funkcji systemu macOS, takich jak Obserwowanie wartości klucza (KVO), powiązanie danych, dane podstawowe, powiązania cocoa i możliwość tworzenia skryptów.

Aby uzyskać więcej informacji, zobacz sekcję Powiązanie danych widoku tabeli w dokumentacji powiązania danych i kodowania klucz-wartość.

Podsumowanie

W tym artykule szczegółowo opatrzono pracę z widokami tabel w aplikacji platformy Xamarin.Mac. Zobaczyliśmy różne typy i zastosowania widoków tabel, sposób tworzenia i obsługi widoków tabel w konstruktorze interfejsu Xcode oraz pracy z widokami tabel w kodzie języka C#.