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.
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:
Spowoduje to otwarcie projektu okna w narzędziu Interface Builder programu Xcode:
Wpisz table
w polu wyszukiwania Inspektora biblioteki, aby ułatwić znajdowanie kontrolek Widok tabeli:
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ń:
Wybierz widok tabeli w hierarchii interfejsu, a następujące właściwości są 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
true
widok tabeli będzie rysować pogrupowane komórki tak, jakby były przestawne. - Kolumny — definiuje liczbę wyświetlanych kolumn.
- Nagłówki — jeśli
true
kolumny będą miały nagłówki. - Zmiana kolejności — jeśli
true
użytkownik będzie mógł przeciągnąć kolejność kolumn w tabeli. - Zmiana rozmiaru — jeśli
true
uż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
true
kiedykolwiek 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
true
użytkownik może wybrać wiele wierszy i kolumn. - Kolumna — jeśli
true
użytkownik może wybrać kolumny. - Typ Wybierz — jeśli
true
użytkownik może wpisać znak, aby wybrać wiersz. - Puste — jeśli
true
użytkownik nie jest wymagany do wybrania wiersza lub kolumny, tabela w ogóle nie zezwala na wybór.
- Wiele — jeśli
- Autozapis — nazwa, w ramach którego format tabel jest zapisywany automatycznie.
- Informacje o kolumnie — jeśli
true
kolejność 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
true
komó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:
- 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
true
użytkownik może edytować komórki w tabeli opartej na komórkach. - Ukryte — jeśli
true
kolumna 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ą Details
kolumnę .
Wybierz widok komórki tabeli (NSTableViewCell
) w hierarchii interfejsu i następujące właściwości są dostępne 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 NSTextField
to ) w hierarchii interfejsu, a następujące właściwości są dostępne 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:
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
true
komórka jest ograniczona do pojedynczego wiersza. - Pierwsza szerokość układu środowiska uruchomieniowego — jeśli
true
komó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
true
komórka może wyświetlać sformatowany i stylizowany tekst. - Cofnij — jeśli
true
komórka przejmuje odpowiedzialność za jego zachowanie cofania.
Wybierz widok komórki tabeli (NSTableFieldCell
) w dolnej części kolumny tabeli w hierarchii interfejsu:
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ć:
Przejdź do Edytora asystentów i upewnij się, że
ViewController.h
plik został wybrany:Wybierz widok tabeli z hierarchii interfejsu, kliknij i przeciągnij do
ViewController.h
pliku.Utwórz gniazdo dla widoku tabeli o nazwie
ProductTable
:Utwórz punkty dla kolumn tabel, a także o nazwie
ProductColumn
iDetailsColumn
: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:
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 ProductTableDelegate
ProductTableDataSource
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ść:
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ść):
Wybierz kolumnęDetails
, wprowadź dla Description
pola Sort Key ( compare:
Klucz sortowania) dla selektora i wybierz pozycję Ascending
Order (Kolejność):
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:
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:
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)
— Zwracatrue
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:
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żyjthis
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żyjthis
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
— ZwracaNSIndexSet
indeksy wybranych wierszy.SelectedRowCount
— Zwraca liczbę wybranych wierszy.IsRowSelected(nint)
— Zwracatrue
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:
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:
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:
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 newColumnIndex
elementu , w przeciwnym razie zwróć wartość false
;
Jeśli uruchomimy aplikację, możemy przeciągnąć nagłówki kolumn, aby zmienić kolejność 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:
Używanie obrazów w widokach tabeli
Aby dołączyć obraz jako część komórki w NSTableView
obiekcie , należy zmienić sposób zwracania danych przez metodę Widoku GetViewForItem
NSTableViewDelegate's
tabeli, aby użyć NSTableCellView
elementu zamiast typowego NSTextField
elementu . 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
:
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ń :
Gdy użytkownik kliknie przycisk Usuń , zostanie wyświetlony alert z prośbą o usunięcie danego wiersza:
Jeśli użytkownik wybierze opcję usunięcia, wiersz zostanie usunięty, a tabela zostanie ponownie wyrysowana:
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#.