Esquema de vistas en Xamarin.Mac

En este artículo, se explica cómo trabajar con vistas de esquema en una aplicación de Xamarin.Mac. Describe cómo crear y mantener vistas de esquema en Xcode e Interface Builder y trabajar con ellas mediante programación.

Cuando se trabaja con C# y .NET en una aplicación de Xamarin.Mac, se tiene acceso a las mismas vistas de tabla que un desarrollador que trabaje en Objective-C y Xcode. Dado que Xamarin.Mac se integra directamente con Xcode, puede usar Interface Builder de Xcode para crear y mantener las vistas de tabla (u opcionalmente crearlas directamente en código C#).

Una vista esquema es un tipo de tabla que permite al usuario expandir o contraer filas de datos jerárquicos. Al igual que una vista de tabla, una vista esquema muestra los datos de un conjunto de elementos relacionados, con filas que representan elementos y columnas individuales que representan los atributos de esos elementos. A diferencia de una vista de tabla, los elementos de una vista esquema no están en una lista plana, se organizan en una jerarquía, como archivos y carpetas en un disco duro.

Una ejecución de aplicación de ejemplo

En este artículo, cubriremos los aspectos básicos del trabajo con vistas de esquema en una aplicación de Xamarin.Mac. Se recomienda encarecidamente primero revisar el artículo Hello, Mac; específicamente las secciones Introducción a Xcode e Interface Builder y Salidas y acciones, ya que se abordan conceptos clave y técnicas que usaremos en este artículo.

También puede echar un vistazo a la sección Exponer clases o métodos de C# a Objective-C del documento sobre el funcionamiento interno de Xamarin.Mac, ya que en ella se explican los atributos Register y Export que se usan para conectar las clases de C# a objetos Objective-C y elementos de la interfaz de usuario.

Introducción a las vistas de esquema

Una vista esquema es un tipo de tabla que permite al usuario expandir o contraer filas de datos jerárquicos. Al igual que una vista de tabla, una vista esquema muestra los datos de un conjunto de elementos relacionados, con filas que representan elementos y columnas individuales que representan los atributos de esos elementos. A diferencia de una vista de tabla, los elementos de una vista esquema no están en una lista plana, se organizan en una jerarquía, como archivos y carpetas en un disco duro.

Si un elemento de una vista Esquema contiene otros elementos, el usuario puede expandirlo o contraerlo. Un elemento expandible muestra un triángulo de divulgación, que apunta a la derecha cuando el elemento se contrae y apunta hacia abajo cuando se expande el elemento. Al hacer clic en el triángulo de divulgación, el elemento se expande o contraiga.

La vista esquema (NSOutlineView) es una subclase de la vista de tabla (NSTableView) y, como tal, hereda gran parte de su comportamiento de su clase primaria. Como resultado, muchas operaciones compatibles con una vista de tabla, como seleccionar filas o columnas, cambiar la posición de las columnas arrastrando encabezados de columna, etc., también son compatibles con una vista esquema. Una aplicación de Xamarin.Mac tiene control de estas características y puede configurar los parámetros de la vista esquema (ya sea en el código o en el Interface Builder) para permitir o denegar determinadas operaciones.

Una vista esquema no almacena sus propios datos, sino que se basa en un origen de datos (NSOutlineViewDataSource) para proporcionar las filas y columnas necesarias, según sea necesario.

El comportamiento de una vista de esquema se puede personalizar proporcionando una subclase del delegado de vista de esquema (NSOutlineViewDelegate) para admitir la administración de columnas outline, el tipo para seleccionar la funcionalidad, la selección de filas y la edición, el seguimiento personalizado y las vistas personalizadas para columnas y filas individuales.

Dado que una vista de esquema comparte gran parte del comportamiento y la funcionalidad con una vista de tabla, es posible que desee pasar por nuestra documentación de vistas de tabla antes de continuar con este artículo.

Creación y mantenimiento de vistas de esquema en Xcode

Al crear una nueva aplicación de Cocoa de Xamarin.Mac, obtendrá una ventana estándar en blanco de forma predeterminada. Esta ventana se define en un archivo .storyboard incluido automáticamente en el proyecto. Para editar el diseño de la ventana, vaya a Explorador de soluciones y haga doble clic en el archivo Main.storyboard:

Selección del guión gráfico principal

Se abrirá el diseño de la ventana en Interface Builder de Xcode:

Edición de la UI en Xcode

Escriba outline en el cuadro de búsqueda del Inspector de biblioteca para facilitar la búsqueda de los controles vista esquema:

Seleccionar una vista de esquema en la biblioteca

Arrastre una vista esquema al controlador de vista en el Editor de interfaz, haga que rellene el área de contenido del controlador de vista y establézcala en donde se reduce y crece con la ventana en el Editorde restricciones:

Editar las restricciones

Seleccione la vista Esquema en la jerarquía de interfaz y las siguientes propiedades están disponibles en el Inspector de atributos:

La captura de pantalla muestra las propiedades disponibles en el Inspector de atributos.

  • Columna esquema: columna de tabla en la que se muestran los datos jerárquicos.
  • Guardar automáticamente columna de esquema: si es true, la columna esquema se guardará y restaurará automáticamente entre las ejecuciones de la aplicación.
  • Sangría: la cantidad de columnas de sangría en un elemento expandido.
  • Sangría sigue las celdas: si es true, el signo de sangría se aplicará sangría junto con las celdas.
  • Autoguardar elementos expandidos: si es true, el estado expandido o contraído de los elementos se guardará y restaurará automáticamente entre ejecuciones de aplicación.
  • Modo de contenido: permite usar vistas (NSView) o celdas (NSCell) para mostrar los datos en las filas y columnas. A partir de macOS 10.7, debe usar vistas.
  • Hacer flotantes las celdas agrupadas: si es true, la vista de tabla dibujará las celdas agrupadas como si fueran flotantes.
  • Columnas: define el número de columnas mostradas.
  • Encabezados: si es true, las columnas tendrán encabezados.
  • Reordenación: si es true, el usuario podrá reordenar las columnas de la tabla arrastrándolas.
  • Cambio de tamaño: si es true, el usuario podrá arrastrar los encabezados de columna para cambiar el tamaño de las columnas.
  • Tamaño de columna: controla la manera en que la tabla dimensionará automáticamente las columnas.
  • Resaltar: controla el tipo de resaltado que se usa en la tabla cuando se selecciona una celda.
  • Alternar filas: si es true, se aplicará un color de fondo diferente a las filas alternas.
  • Cuadrícula horizontal: selecciona el tipo de borde dibujado horizontalmente entre las celdas.
  • Cuadrícula vertical: selecciona el tipo de borde dibujado verticalmente entre las celdas.
  • Color de cuadrícula: establece el color del borde de celda.
  • Fondo: establece el color de fondo de la celda.
  • Selección: permite controlar cómo puede el usuario seleccionar celdas en la tabla de la siguiente forma:
    • Múltiple: si es true, el usuario puede seleccionar varias filas y columnas.
    • Columna: si es true, el usuario puede seleccionar columnas.
    • Escribir para seleccionar, si es true, el usuario puede escribir un carácter para seleccionar una fila.
    • Vacío: si es true, no es necesario que el usuario seleccione una fila o columna, la tabla no permite ninguna selección.
  • Guardar automáticamente: el nombre con el que se guarda automáticamente el formato de las tablas.
  • Información de columna: si es true, el orden y el ancho de las columnas se guardarán automáticamente.
  • Saltos de línea: seleccione cómo controla la celda los saltos de línea.
  • Trunca la última línea visible: si es true, la celda se truncará si los datos no caben dentro de sus límites.

Importante

A menos que mantenga una aplicación heredada de Xamarin.Mac, NSView se deben usar vistas de esquema basadas en NSCell vistas de tabla basadas. NSCell se considera heredado y es posible que no se admita en el futuro.

Seleccione una columna de tabla en la jerarquía de la interfaz: las siguientes propiedades estarán disponibles en el Inspector de atributos:

Captura de pantalla que muestra las propiedades disponibles para la columna de tabla seleccionada en el Inspector de atributos.

  • Título: establece el título de la columna.
  • Alineación: establece la alineación del texto dentro de las celdas.
  • Fuente de título: selecciona la fuente del texto de encabezado de la celda.
  • Clave de ordenación: la clave que se usa para ordenar los datos de la columna. Dejar en blanco si el usuario no puede ordenar esta columna.
  • Selector: la acción que se usa para realizar la ordenación. Dejar en blanco si el usuario no puede ordenar esta columna.
  • Orden: el criterio de ordenación de los datos de columnas.
  • Cambio de tamaño: selecciona el tipo de cambio de tamaño de la columna.
  • Editable: si es true, el usuario puede editar las celdas en una tabla basada en celdas.
  • Oculta: si es true, la columna está oculta.

También puede cambiar el tamaño de la columna arrastrando el control (centrado verticalmente en el lado derecho de la columna) hacia la izquierda o la derecha.

Vamos a seleccionar cada columna de la vista de tabla y asignar a la primera columna el título Product y a la segunda Details.

Seleccione una vista de celda de tabla (NSTableViewCell) en la jerarquía de la interfaz: las siguientes propiedades estarán disponibles en el Inspector de atributos:

Captura de pantalla que muestra las propiedades disponibles para la celda de tabla seleccionada en el Inspector de atributos.

Estas son todas las propiedades de una vista estándar. Aquí también tiene la opción de cambiar el tamaño de las filas de esta columna.

Seleccione una vista de celda de tabla (de forma predeterminadas, es un NSTextField) en la jerarquía de la interfaz: las siguientes propiedades estarán disponibles en el Inspector de atributos:

Captura de pantalla que muestra las propiedades disponibles para la celda de vista de tabla seleccionada en el Inspector de atributos.

Aquí podrá establecer todas las propiedades de un campo de texto estándar. De forma predeterminada, se usa un campo de texto estándar para mostrar los datos de una celda de una columna.

Seleccione una vista de celda de tabla (NSTableFieldCell) en la jerarquía de la interfaz: las siguientes propiedades estarán disponibles en el Inspector de atributos:

Captura de pantalla que muestra las propiedades disponibles para la celda de vista de tabla seleccionada.

Las opciones más importantes son:

  • Diseño: seleccione el diseño que tendrán las celdas de esta columna.
  • Usa el modo de línea única: si es true, la celda se limita a una sola línea.
  • Ancho del diseño en la primera ejecución: si es true, la celda se ajusta al ancho establecido (ya sea manual o automáticamente) la primera vez que se ejecuta la aplicación.
  • Acción: controla cuando se envía la acción de edición de la celda.
  • Comportamiento: define si una celda es seleccionable o editable.
  • Texto enriquecido: si es true, la celda puede mostrar texto con formato y estilo.
  • Deshacer: si es true, la celda asume la responsabilidad del comportamiento de deshacer.

Seleccione la vista de celda de tabla (NSTableFieldCell) en la parte inferior de una columna de tabla en la jerarquía de la interfaz:

Seleccionar la vista Celda de tabla

Esto le permite editar la vista celda de tabla usada como patrón base para todas las celdas creadas para la columna especificada.

Adición de acciones y salidas

Al igual que cualquier otro control de la interfaz de usuario de Cocoa, es necesario exponer nuestra vista esquema y sus columnas y celdas al código de C# mediante Acciones y salidas (en función de la funcionalidad necesaria).

El proceso es el mismo para cualquier elemento vista de esquema que deseemos exponer:

  1. Cambie al Editor del Asistente y asegúrese de que el archivo ViewController.h esté seleccionado:

    Seleccionar el archivo .h correcto

  2. Seleccione la vista Esquema en la jerarquía de interfaz, haga clic con el control y arrástrela al ViewController.h archivo.

  3. Cree una salida para la vista Esquema denominada ProductOutline:

    Captura de pantalla que muestra una salida denominada ProductOutline en el Inspector de atributos.

  4. Cree también salidas para las columnas de tabla y denomínelas ProductColumn y DetailsColumn:

    Captura de pantalla que muestra una salida denominada DetailsColumn en el Inspector de atributos.

  5. Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

A continuación, escribiremos el código para mostrar algunos datos para el esquema cuando se ejecute la aplicación.

Rellenar la vista esquema

Con nuestra vista esquema diseñada en el Interface Builder y expuesta a través de una salida, a continuación necesitamos crear el código de C# para rellenarlo.

En primer lugar, vamos a crear una nueva Product clase para almacenar la información de las filas individuales y los grupos de productos secundarios. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar>Nuevo archivo.... Seleccione General>Clase vacía, escriba Product para el Nombre y haga clic en el botón Nuevo:

Creación de una clase vacía

Edite el archivo Product.cs para que quede de la siguiente manera:

using System;
using Foundation;
using System.Collections.Generic;

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

        #region Computed Properties
        public string Title { get; set;} = "";
        public string Description { get; set;} = "";
        public bool IsProductGroup {
            get { return (Products.Count > 0); }
        }
        #endregion

        #region Constructors
        public Product ()
        {
        }

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

A continuación, es necesario crear una subclase de NSOutlineDataSource para proporcionar los datos de nuestro esquema tal como se solicita. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar>Nuevo archivo.... Seleccione General>Clase vacía, escriba ProductOutlineDataSource para el Nombre y haga clic en el botón Nuevo.

Edite el archivo ProductTableDataSource.cs para que quede de la siguiente manera:

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

namespace MacOutlines
{
    public class ProductOutlineDataSource : NSOutlineViewDataSource
    {
        #region Public Variables
        public List<Product> Products = new List<Product>();
        #endregion

        #region Constructors
        public ProductOutlineDataSource ()
        {
        }
        #endregion

        #region Override Methods
        public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item)
        {
            if (item == null) {
                return Products.Count;
            } else {
                return ((Product)item).Products.Count;
            }

        }

        public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item)
        {
            if (item == null) {
                return Products [childIndex];
            } else {
                return ((Product)item).Products [childIndex];
            }

        }

        public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
        {
            if (item == null) {
                return Products [0].IsProductGroup;
            } else {
                return ((Product)item).IsProductGroup;
            }

        }
        #endregion
    }
}

Esta clase tiene almacenamiento para los elementos de la vista Esquema e invalida para GetChildrenCount devolver el número de filas de la tabla. GetChild devuelve un elemento primario o secundario específico (según lo solicitado por la vista Esquema) y ItemExpandable define el elemento especificado como elemento primario o secundario.

Por último, es necesario crear una subclase de NSOutlineDelegate para proporcionar el comportamiento de nuestro esquema. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar>Nuevo archivo.... Seleccione General>Clase vacía, escriba ProductOutlineDelegate para el Nombre y haga clic en el botón Nuevo.

Edite el archivo ProductOutlineDelegate.cs para que quede de la siguiente manera:

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

namespace MacOutlines
{
    public class ProductOutlineDelegate : NSOutlineViewDelegate
    {
        #region Constants
        private const string CellIdentifier = "ProdCell";
        #endregion

        #region Private Variables
        private ProductOutlineDataSource DataSource;
        #endregion

        #region Constructors
        public ProductOutlineDelegate (ProductOutlineDataSource datasource)
        {
            this.DataSource = datasource;
        }
        #endregion

        #region Override Methods

        public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
            // 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)outlineView.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;
            }

            // Cast item
            var product = item as Product;

            // Setup view based on the column selected
            switch (tableColumn.Title) {
            case "Product":
                view.StringValue = product.Title;
                break;
            case "Details":
                view.StringValue = product.Description;
                break;
            }

            return view;
        }
        #endregion
    }
}

Cuando creamos una instancia de ProductOutlineDelegate, también pasamos una instancia de que ProductOutlineDataSource proporciona los datos para el esquema. El método GetView es responsable de devolver una vista (datos) para mostrar la celda de una columna y una fila determinadas. Si es posible, se reutilizará una vista existente para mostrar la celda. De lo contrario, se debe crear una nueva vista.

Para rellenar el esquema, vamos a editar el MainWindow.cs archivo y hacer que el AwakeFromNib método tenga un aspecto similar al siguiente:

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

    // Create data source and populate
    var DataSource = new ProductOutlineDataSource ();

    var Vegetables = new Product ("Vegetables", "Greens and Other Produce");
    Vegetables.Products.Add (new Product ("Cabbage", "Brassica oleracea - Leaves, axillary buds, stems, flowerheads"));
    Vegetables.Products.Add (new Product ("Turnip", "Brassica rapa - Tubers, leaves"));
    Vegetables.Products.Add (new Product ("Radish", "Raphanus sativus - Roots, leaves, seed pods, seed oil, sprouting"));
    Vegetables.Products.Add (new Product ("Carrot", "Daucus carota - Root tubers"));
    DataSource.Products.Add (Vegetables);

    var Fruits = new Product ("Fruits", "Fruit is a part of a flowering plant that derives from specific tissues of the flower");
    Fruits.Products.Add (new Product ("Grape", "True Berry"));
    Fruits.Products.Add (new Product ("Cucumber", "Pepo"));
    Fruits.Products.Add (new Product ("Orange", "Hesperidium"));
    Fruits.Products.Add (new Product ("Blackberry", "Aggregate fruit"));
    DataSource.Products.Add (Fruits);

    var Meats = new Product ("Meats", "Lean Cuts");
    Meats.Products.Add (new Product ("Beef", "Cow"));
    Meats.Products.Add (new Product ("Pork", "Pig"));
    Meats.Products.Add (new Product ("Veal", "Young Cow"));
    DataSource.Products.Add (Meats);

    // Populate the outline
    ProductOutline.DataSource = DataSource;
    ProductOutline.Delegate = new ProductOutlineDelegate (DataSource);

}

Si ejecutamos la aplicación, se muestra lo siguiente:

Vista contraída

Si expandimos un nodo en la vista Esquema, tendrá un aspecto similar al siguiente:

Vista expandida

Ordenación por columna

Vamos a permitir que el usuario ordene los datos en el esquema haciendo clic en un encabezado de columna. En primer lugar, haga doble clic en el archivo Main.storyboard para abrirlo y editarlo en Interface Builder. Seleccione la columna Product, escriba Title para la Clave de ordenación y compare: para el Selector y seleccione Ascending para el Orden:

Establecer el criterio de ordenación de la clave

Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

Ahora vamos a editar el archivo ProductOutlineDataSource.cs y agregar los métodos siguientes:

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

public override void SortDescriptorsChanged (NSOutlineView outlineView, NSSortDescriptor[] oldDescriptors)
{
    // Sort the data
    Sort (oldDescriptors [0].Key, oldDescriptors [0].Ascending);
    outlineView.ReloadData ();
}

El método Sort nos permite ordenar los datos en el origen de datos en función de un campo de clase de Product determinado en orden ascendente o descendente. Se llamará al método SortDescriptorsChanged invalidado cada vez que el usuario haga clic en un encabezado de columna. Se pasará el valor de Clave establecido en Interface Builder y el criterio de ordenación de esa columna.

Si ejecutamos la aplicación y hacemos clic en un encabezado de columna, las filas se ordenarán por esa columna:

Ejemplo de salida ordenada

Selección de fila

Si quiere permitir que el usuario seleccione una sola fila, haga doble clic en el archivo Main.storyboard para abrirlo y editarlo en Interface Builder. Active la vista Esquema en la jerarquía de interfaz y desactive la casilla Multiple (Varios) en el Inspectorde atributos:

Captura de pantalla que muestra el Inspector de atributos en el que puede cambiar la configuración Múltiple.

Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

A continuación, edite el archivo ProductOutlineDelegate.cs y agregue el método siguiente:

public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
{
    // Don't select product groups
    return !((Product)item).IsProductGroup;
}

Esto permitirá al usuario seleccionar cualquier fila única en la vista Esquema. Devuelve false para ShouldSelectItem cualquier elemento que no quieras que el usuario pueda seleccionar o false para cada elemento si no quieres que el usuario pueda seleccionar ningún elemento.

Selección de varias filas

Si quiere permitir que el usuario seleccione varias filas, haga doble clic en el archivo Main.storyboard para abrirlo y editarlo en Interface Builder. Active la vista Esquema en la jerarquía de interfaz y active la casilla Múltiple en el Inspector de atributos:

Captura de pantalla que muestra el Inspector de atributos, donde puede seleccionar Múltiple.

Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

A continuación, edite el archivo ProductOutlineDelegate.cs y agregue el método siguiente:

public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
{
    // Don't select product groups
    return !((Product)item).IsProductGroup;
}

Esto permitirá al usuario seleccionar cualquier fila única en la vista Esquema. Devuelve false para ShouldSelectRow cualquier elemento que no quieras que el usuario pueda seleccionar o false para cada elemento si no quieres que el usuario pueda seleccionar ningún elemento.

Escribir para seleccionar fila

Si desea permitir que el usuario escriba un carácter con la vista Esquema seleccionada y seleccione la primera fila que tiene ese carácter, haga doble clic en el Main.storyboard archivo para abrirlo para editarlo en el Interface Builder. Active la vista Esquema en la jerarquía de interfaz y active la casilla Type Select (Seleccionar tipo) en el Inspector de atributos:

Editar el tipo de fila

Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

Ahora vamos a editar el archivo ProductOutlineDelegate.cs y agregar el método siguiente:

public override NSObject GetNextTypeSelectMatch (NSOutlineView outlineView, NSObject startItem, NSObject endItem, string searchString)
{
    foreach(Product product in DataSource.Products) {
        if (product.Title.Contains (searchString)) {
            return product;
        }
    }

    // Not found
    return null;
}

El GetNextTypeSelectMatch método toma el objeto especificado searchString y devuelve el elemento del primero Product que tiene esa cadena en Title.

Reordenación de columnas

Si desea permitir que el usuario arrastre las columnas de reordenación en la vista Esquema, haga doble clic en el Main.storyboard archivo para abrirlo para editarlo en el Interface Builder. Active la vista Esquema en la jerarquía de interfaz y active la casilla Reordenar en el Inspector de atributos:

Captura de pantalla que muestra el Inspector de atributos, donde puede seleccionar Reordenar.

Si se proporciona un valor para la propiedad Guardar automáticamente y se activa el campo Información de columna, los cambios realizados en el diseño de la tabla se guardarán automáticamente y se restaurarán la próxima vez que se ejecute la aplicación.

Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.

Ahora vamos a editar el archivo ProductOutlineDelegate.cs y agregar el método siguiente:

public override bool ShouldReorder (NSOutlineView outlineView, nint columnIndex, nint newColumnIndex)
{
    return true;
}

El método ShouldReorder debe devolver true para cualquier columna que se pueda arrastrar para reordenar en newColumnIndex, en caso contrario devolverá false.

Si ejecutamos la aplicación, podemos arrastrar los encabezados de columna para reordenar las columnas:

Ejemplo de reordenación de columnas

Edición de celdas

Si quiere permitir que el usuario edite los valores de una celda determinada, edite el archivo ProductOutlineDelegate.cs y cambie el método GetViewForItem de la siguiente manera:

public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
    // Cast item
    var product = item as Product;

    // 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)outlineView.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 = !product.IsProductGroup;
    }

    // Tag view
    view.Tag = outlineView.RowForItem (item);

    // Allow for edit
    view.EditingEnded += (sender, e) => {

        // Grab product
        var prod = outlineView.ItemAtRow(view.Tag) as Product;

        // Take action based on type
        switch(view.Identifier) {
        case "Product":
            prod.Title = view.StringValue;
            break;
        case "Details":
            prod.Description = view.StringValue;
            break;
        }
    };

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.StringValue = product.Title;
        break;
    case "Details":
        view.StringValue = product.Description;
        break;
    }

    return view;
}

Ahora, si ejecutamos la aplicación, el usuario puede editar las celdas en la vista de tabla:

Ejemplo de edición de celdas

Uso de imágenes en vistas de esquema

Para incluir una imagen como parte de la celda en , NSOutlineViewdeberá cambiar cómo devuelven los datos el método de NSTableViewDelegate's GetView la vista esquema para usar en NSTableCellView lugar del típico NSTextField. Por ejemplo:

public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
    // Cast item
    var product = item as Product;

    // 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)outlineView.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 = !product.IsProductGroup;
    }

    // Tag view
    view.TextField.Tag = outlineView.RowForItem (item);

    // Allow for edit
    view.TextField.EditingEnded += (sender, e) => {

        // Grab product
        var prod = outlineView.ItemAtRow(view.Tag) as Product;

        // Take action based on type
        switch(view.Identifier) {
        case "Product":
            prod.Title = view.TextField.StringValue;
            break;
        case "Details":
            prod.Description = view.TextField.StringValue;
            break;
        }
    };

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.ImageView.Image = NSImage.ImageNamed (product.IsProductGroup ? "tags.png" : "tag.png");
        view.TextField.StringValue = product.Title;
        break;
    case "Details":
        view.TextField.StringValue = product.Description;
        break;
    }

    return view;
}

Para más información, consulte la sección Uso de imágenes con vistas de esquema de nuestra documentación Trabajar con imágenes.

Vistas de esquema de enlace de datos

Mediante el uso de técnicas de codificación de clave-valor y enlace de datos en la aplicación de Xamarin.Mac, puede reducir considerablemente la cantidad de código que tiene que escribir y mantener para rellenar y trabajar con elementos de la interfaz de usuario. También tiene la ventaja de poder desacoplar aún más los datos de respaldo (Modelo de datos) de la interfaz de usuario de front-end (Modelo-Vista-Controlador), lo que facilita el mantenimiento y hace que el diseño de las aplicaciones sea más flexible.

La codificación de clave-valor (KVC) es un mecanismo para acceder indirectamente a las propiedades de un objeto mediante claves (cadenas con formato especial) para identificar propiedades en lugar de acceder a ellas a través de variables de instancia o métodos de descriptor de acceso (get/set). Al implementar descriptores de acceso compatibles con la codificación de clave-valor en la aplicación de Xamarin.Mac, obtendrá acceso a otras características de macOS, como la observación de clave-valor (KVO), el enlace de datos, Core Data, enlaces de Cocoa y la capacidad de ejecución mediante scripts.

Para obtener más información, consulte la sección Enlace de datos de la vista esquema de nuestra documentación de enlace de datos y codificación de clave-valor.

Resumen

En este artículo se ha realizado un vistazo detallado al trabajo con vistas de esquema en una aplicación de Xamarin.Mac. Hemos visto los diferentes tipos y usos de vistas de esquema, cómo crear y mantener vistas de esquema en el Interface Builder de Xcode y cómo trabajar con vistas de esquema en código de C#.