Diseño de la interfaz de usuario .storyboard/.xib-less en Xamarin.Mac

En este artículo se trata la creación de una interfaz de usuario de una aplicación xamarin.Mac directamente desde código de C#, sin archivos .storyboard, archivos .xib o Interface Builder.

Información general

Al trabajar con C# y .NET en una aplicación de Xamarin.Mac, tiene acceso a los mismos elementos y herramientas de la interfaz de usuario que un desarrollador que trabaja en Objective-CObjective-C Normalmente, al crear una aplicación de Xamarin.Mac, usará el archivo Interface Builder de Xcode con archivos .storyboard o .xib para crear y mantener la interfaz de usuario de la aplicación.

También tiene la opción de crear parte o toda la interfaz de usuario de la aplicación de Xamarin.Mac directamente en código de C#. En este artículo, se tratarán los conceptos básicos de la creación de interfaces de usuario y elementos de interfaz de usuario en código de C#.

Editor de Visual Studio para Mac código de Visual Studio para Maceditor de

Cambio de una ventana para usar código

Cuando se crea una nueva aplicación Xamarin.Mac Cocoa, se obtiene una ventana estándar en blanco de forma predeterminada. Esta ventana se define en un archivo Main.storyboard (o tradicionalmente un archivo MainWindow.xib)incluido automáticamente en el proyecto. Esto también incluye un archivo ViewController.cs que administra la vista principal de la aplicación (o de nuevo tradicionalmente un archivo MainWindow.cs y MainWindowController.cs).

Para cambiar a una ventana Xibless para una aplicación, haga lo siguiente:

  1. Abra la aplicación que desea dejar de usar .storyboard o archivos .xib para definir la interfaz de usuario en Visual Studio para Mac.

  2. En la Panel de solución, haga clic con el botón derecho en el archivo Main.storyboard o MainWindow.xib y seleccione Quitar:

    Quitar el guión gráfico principal o la ventana

  3. En el cuadro de diálogo Quitar, haga clic en el botón Eliminar para quitar completamente el archivo .storyboard o .xib del proyecto:

    Confirmación de la eliminación

Ahora es necesario modificar el archivo MainWindow.cs para definir el diseño de la ventana y modificar el archivo ViewController.cs o MainWindowController.cs para crear una instancia de nuestra clase, ya que ya no se usa el archivo .storyboard o .xib.

Es posible que las aplicaciones modernas de Xamarin.Mac que usan guiones gráficos para su interfaz de usuario no incluyan automáticamente los archivos MainWindow.cs,ViewController.cso MainWindowController.cs. Según sea necesario, simplemente agregue una nueva clase vacía de C# al proyecto (Agregarnuevo archivo...GeneralClase vacía) y así mismo se le asigne el mismo nombre que el archivo que falta.

Definición de la ventana en el código

A continuación, edite el archivo MainWindow.cs y haga que sea parecido al siguiente:

using System;
using Foundation;
using AppKit;
using CoreGraphics;

namespace MacXibless
{
    public partial class MainWindow : NSWindow
    {
        #region Private Variables
        private int NumberOfTimesClicked = 0;
        #endregion

        #region Computed Properties
        public NSButton ClickMeButton { get; set;}
        public NSTextField ClickMeLabel { get ; set;}
        #endregion

        #region Constructors
        public MainWindow (IntPtr handle) : base (handle)
        {
        }

        [Export ("initWithCoder:")]
        public MainWindow (NSCoder coder) : base (coder)
        {
        }

        public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
            // Define the user interface of the window here
            Title = "Window From Code";

            // Create the content view for the window and make it fill the window
            ContentView = new NSView (Frame);

            // Add UI elements to window
            ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
                AutoresizingMask = NSViewResizingMask.MinYMargin
            };
            ContentView.AddSubview (ClickMeButton);

            ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
                BackgroundColor = NSColor.Clear,
                TextColor = NSColor.Black,
                Editable = false,
                Bezeled = false,
                AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
                StringValue = "Button has not been clicked yet."
            };
            ContentView.AddSubview (ClickMeLabel);
        }
        #endregion

        #region Override Methods
        public override void AwakeFromNib ()
        {
            base.AwakeFromNib ();

            // Wireup events
            ClickMeButton.Activated += (sender, e) => {
                // Update count
                ClickMeLabel.StringValue = (++NumberOfTimesClicked == 1) ? "Button clicked one time." : string.Format("Button clicked {0} times.",NumberOfTimesClicked);
            };
        }
        #endregion

    }
}

Vamos a analizar algunos de los elementos clave.

En primer lugar, agregamos algunas propiedades calculadas que actuarán como salidas (como si la ventana se hubiera creado en un archivo .storyboard o .xib):

public NSButton ClickMeButton { get; set;}
public NSTextField ClickMeLabel { get ; set;}

Esto nos dará acceso a los elementos de la interfaz de usuario que vamos a mostrar en la ventana. Puesto que la ventana no se infla desde un archivo .storyboard o .xib, necesitamos una manera de crear una instancia de él (como veremos más adelante en la MainWindowController clase ). Esto es lo que hace este nuevo método de constructor:

public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
    ...
}

Aquí es donde diseñaremos el diseño de la ventana y colocaremos los elementos de interfaz de usuario necesarios para crear la interfaz de usuario necesaria. Para poder agregar elementos de interfaz de usuario a una ventana, necesita una vista de contenido que contenga los elementos:

ContentView = new NSView (Frame);

Esto crea una vista de contenido que rellenará la ventana. Ahora agregamos nuestro primer elemento de interfaz de usuario, NSButton un , a la ventana:

ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
    AutoresizingMask = NSViewResizingMask.MinYMargin
};
ContentView.AddSubview (ClickMeButton);

Lo primero que hay que tener en cuenta aquí es que, a diferencia de iOS, macOS usa la notación matemática para definir su sistema de coordenadas de ventana. Por lo tanto, el punto de origen está en la esquina inferior izquierda de la ventana, con valores aumentando a la derecha y hacia la esquina superior derecha de la ventana. Cuando creamos el nuevo , lo tenemos en cuenta NSButton a medida que definimos su posición y tamaño en pantalla.

La propiedad indica al botón que queremos que permanezca en la misma ubicación desde la parte superior de la ventana cuando se cambia el tamaño de la AutoresizingMask = NSViewResizingMask.MinYMargin ventana verticalmente. De nuevo, esto es necesario porque (0,0) está en la parte inferior izquierda de la ventana.

Por último, el método agrega a la vista de contenido para que se muestre en pantalla cuando se ejecute la aplicación y se muestre ContentView.AddSubview (ClickMeButton)NSButton la ventana.

A continuación, se agrega una etiqueta a la ventana que mostrará el número de veces que NSButton se ha hecho clic en :

ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
    BackgroundColor = NSColor.Clear,
    TextColor = NSColor.Black,
    Editable = false,
    Bezeled = false,
    AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
    StringValue = "Button has not been clicked yet."
};
ContentView.AddSubview (ClickMeLabel);

Puesto que macOS no tiene un elemento específico de la interfaz de usuario Label, hemos agregado un elemento con un estilo especial y no editable para que actúe como etiqueta. Al igual que el botón anterior, el tamaño y la ubicación tiene en cuenta que (0,0) está en la parte inferior izquierda de la ventana. La AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin propiedad usa el operador AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin para combinar dos NSViewResizingMask características. Esto hará que la etiqueta permanezca en la misma ubicación desde la parte superior de la ventana cuando se cambie el tamaño de la ventana verticalmente y se reduzca y aumente de ancho a medida que la ventana cambia de tamaño horizontalmente.

De nuevo, el método agrega a la vista de contenido para que se muestre en pantalla cuando se ejecute la aplicación ContentView.AddSubview (ClickMeLabel) y se abra la NSTextField ventana.

Ajustar el controlador de ventana

Dado que el diseño de ya no se carga desde un archivo .storyboard o .xib, es necesario realizar algunos ajustes en el MainWindow controlador de ventana. Edite el archivo MainWindowController.cs y haga que sea parecido al siguiente:

using System;

using Foundation;
using AppKit;
using CoreGraphics;

namespace MacXibless
{
    public partial class MainWindowController : NSWindowController
    {
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }

        [Export ("initWithCoder:")]
        public MainWindowController (NSCoder coder) : base (coder)
        {
        }

        public MainWindowController () : base ("MainWindow")
        {
            // Construct the window from code here
            CGRect contentRect = new CGRect (0, 0, 1000, 500);
            base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);

            // Simulate Awaking from Nib
            Window.AwakeFromNib ();
        }

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

        public new MainWindow Window {
            get { return (MainWindow)base.Window; }
        }
    }
}

Vamos a analizar los elementos clave de esta modificación.

En primer lugar, definimos una nueva instancia de la clase y la asignamos a la propiedad del controlador MainWindow de ventana Window base:

CGRect contentRect = new CGRect (0, 0, 1000, 500);
base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);

Definimos la ubicación de la ventana de pantalla con CGRect un . Al igual que el sistema de coordenadas de la ventana, la pantalla define (0,0) como la esquina inferior izquierda. A continuación, definimos el estilo de la ventana mediante el operador Or para combinar dos o más características:

... (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable) ...

Están disponibles NSWindowStyle las siguientes características:

  • Sin borde: la ventana no tendrá ningún borde.
  • Titled: la ventana tendrá una barra de título.
  • Intercambiable: la ventana tiene un botón Cerrar y se puede cerrar.
  • Miniaturizable: la ventana tiene un botón miniaturizar y se puede minimizar.
  • Cambiar tamaño: la ventana tendrá un botón Cambiar tamaño y se puede cambiar el tamaño.
  • Utilidad: la ventana es una ventana de estilo de la utilidad (panel).
  • DocModal: si la ventana es un panel, será Modal de documento en lugar de Modal del sistema.
  • NonactivatingPanel: si la ventana es un panel, no se convertiría en la ventana principal.
  • TexturedBackground: la ventana tendrá un fondo con textura.
  • Sin escalar: la ventana no se escalará.
  • UnifiedTitleAndToolbar: se unirán las áreas de título y barra de herramientas de la ventana.
  • Hud: la ventana se mostrará como un panel de pantalla frontal.
  • FullScreenWindow: la ventana puede entrar en modo de pantalla completa.
  • FullSizeContentView: la vista de contenido de la ventana está detrás del título y el área de la barra de herramientas.

Las dos últimas propiedades definen el tipo de almacenamiento en búfer para la ventana y si se aplazará el dibujo de la ventana. Para obtener más información sobre , consulte la documentación introducción NSWindows a apple NSWindows

Por último, dado que la ventana no se infla desde un archivo .storyboard o .xib, es necesario simularlo en MainWindowController.cs llamando al método windows:

Window.AwakeFromNib ();

Esto le permitirá codificar en la ventana como una ventana estándar cargada desde un archivo .storyboard o .xib.

Mostrar la ventana

Con el archivo .storyboard o .xib quitado y los archivos MainWindow.cs y MainWindowController.cs modificados, se usa la ventana del mismo modo que cualquier ventana normal que se haya creado en el archivo Interface Builder de Xcode con un archivo .xib.

A continuación se creará una nueva instancia de la ventana y su controlador y se mostrará la ventana en pantalla:

private MainWindowController mainWindowController;
...

mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);

En este momento, si se ejecuta la aplicación y se hace clic en el botón un par de veces, se mostrará lo siguiente:

Ejecución de una aplicación de ejemplo Ejecuciónde una aplicación de

Agregar una ventana de solo código

Si solo queremos agregar un código, una ventana de xibless a una aplicación existente de Xamarin.Mac, haga clic con el botón derecho en el proyecto en la Panel de solución y seleccione Agregarnuevo archivo. . En el cuadro de diálogo Nuevo archivo, elija Xamarin.Mac Cocoa Window with Controller (Ventana de Cocoa de Xamarin.Maccon controlador),como se muestra a continuación:

Adición de un nuevo controlador de ventana

Al igual que antes, eliminaremos el archivo .storyboard o .xib predeterminado del proyecto (en este caso SecondWindow.xib)y seguiremos los pasos descritos en la sección Switching a Window to use Code anterior para cubrir la definición de la ventana al código.

Agregar un elemento de interfaz de usuario a una ventana en el código

Tanto si se creó una ventana en código como si se cargó desde un archivo .storyboard o .xib, puede haber ocasiones en las que se quiera agregar un elemento de interfaz de usuario a una ventana desde el código. Por ejemplo:

var ClickMeButton = new NSButton (new CGRect (10, 10, 100, 30)){
    AutoresizingMask = NSViewResizingMask.MinYMargin
};
MyWindow.ContentView.AddSubview (ClickMeButton);

El código anterior crea un nuevo objeto y lo agrega a NSButton la instancia de ventana para MyWindow mostrarlo. Básicamente, cualquier elemento de interfaz de usuario que se pueda definir en el Interface Builder de Xcode en un archivo .storyboard o .xib se puede crear en el código y mostrarse en una ventana.

Definición de la barra de menús en el código

Debido a las limitaciones actuales de Xamarin.Mac, no se recomienda crear la barra de menús de la aplicación Xamarin.Mac, en el código, pero seguir usando el archivo NSMenuBarNSMenuBar o MainMenu.xib para definirlo. Dicho esto, puede agregar y quitar menús y elementos de menú en código de C#.

Por ejemplo, edite el archivo AppDelegate.cs y haga que el método sea parecido al siguiente:

public override void DidFinishLaunching (NSNotification notification)
{
    mainWindowController = new MainWindowController ();
    mainWindowController.Window.MakeKeyAndOrderFront (this);

    // Create a Status Bar Menu
    NSStatusBar statusBar = NSStatusBar.SystemStatusBar;

    var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable);
    item.Title = "Phrases";
    item.HighlightMode = true;
    item.Menu = new NSMenu ("Phrases");

    var address = new NSMenuItem ("Address");
    address.Activated += (sender, e) => {
        Console.WriteLine("Address Selected");
    };
    item.Menu.AddItem (address);

    var date = new NSMenuItem ("Date");
    date.Activated += (sender, e) => {
        Console.WriteLine("Date Selected");
    };
    item.Menu.AddItem (date);

    var greeting = new NSMenuItem ("Greeting");
    greeting.Activated += (sender, e) => {
        Console.WriteLine("Greetings Selected");
    };
    item.Menu.AddItem (greeting);

    var signature = new NSMenuItem ("Signature");
    signature.Activated += (sender, e) => {
        Console.WriteLine("Signature Selected");
    };
    item.Menu.AddItem (signature);
}

Lo anterior crea un menú barra de estado a partir del código y lo muestra cuando se inicia la aplicación. Para obtener más información sobre cómo trabajar con menús, consulte nuestra documentación de menús.

Resumen

En este artículo se ha realizado un análisis detallado de la creación de la interfaz de usuario de una aplicación de Xamarin.Mac en código de C# en lugar de usar el Interface Builder de Xcode con archivos .storyboard o .xib.