.storyboard/.xib-less Benutzeroberflächendesign in Xamarin.Mac

In diesem Artikel wird die Erstellung der Benutzeroberfläche einer Xamarin.Mac-Anwendung direkt aus C#-Code ohne Storyboarddateien, XIB-Dateien oder Schnittstellen-Generator behandelt.

Übersicht

Beim Arbeiten mit C# und .NET in einer Xamarin.Mac-Anwendung haben Sie Zugriff auf die gleichen Benutzeroberflächenelemente und -tools, die ein Entwickler ausführt Objective-C und Xcode ausführt. Normalerweise verwenden Sie beim Erstellen einer Xamarin.Mac-Anwendung den Schnittstellen-Generator von Xcode mit .storyboard- oder XIB-Dateien, um die Benutzeroberfläche der Anwendung zu erstellen und zu Standard.

Sie haben auch die Möglichkeit, einige oder alle Ui Ihrer Xamarin.Mac-Anwendung direkt im C#-Code zu erstellen. In diesem Artikel werden die Grundlagen des Erstellens von Benutzeroberflächen und UI-Elementen im C#-Code behandelt.

The Visual Studio for Mac code editor

Wechseln eines Fensters zur Verwendung von Code

Wenn Sie eine neue Xamarin.Mac Cocoa-Anwendung erstellen, erhalten Sie standardmäßig ein standardmäßig leeres Fenster. Diese Fenster werden in einer Main.Storyboard-Datei (oder traditionell einer MainWindow.xib)-Datei definiert, die automatisch im Projekt enthalten ist. Dies umfasst auch eine ViewController.cs Datei, die die Standard Ansicht der App verwaltet (oder wieder traditionell eine MainWindow.cs und eine MainWindowController.cs Datei).

Gehen Sie wie folgt vor, um zu einem Xibless-Fenster für eine Anwendung zu wechseln:

  1. Öffnen Sie die Anwendung, die Sie nicht mehr verwenden .storyboard möchten, oder XIB-Dateien, um die Benutzeroberfläche in Visual Studio für Mac zu definieren.

  2. Klicken Sie auf dem Lösungspad mit der rechten Maustaste auf die Datei "Main.storyboard" oder "MainWindow.xib", und wählen Sie "Entfernen" aus:

    Removing the main storyboard or window

  3. Klicken Sie im Dialogfeld "Entfernen" auf die Schaltfläche "Löschen ", um das Storyboard oder XIB vollständig aus dem Projekt zu entfernen:

    Confirming the deletion

Jetzt müssen wir die MainWindow.cs Datei ändern, um das Layout des Fensters zu definieren und die ViewController.cs - oder MainWindowController.cs-Datei zu ändern, um eine Instanz unserer MainWindow Klasse zu erstellen, da wir die STORYBOARD- oder XIB-Datei nicht mehr verwenden.

Moderne Xamarin.Mac-Apps, die Storyboards für ihre Benutzeroberfläche verwenden, enthalten möglicherweise nicht automatisch die dateien MainWindow.cs, ViewController.cs oder MainWindowController.cs . Fügen Sie dem Projekt einfach eine neue leere C#-Klasse hinzu (Neue Datei hinzufügen...>>General>Empty Class) and name it the same as the missing file.

Definieren des Fensters im Code

Bearbeiten Sie als Nächstes die MainWindow.cs Datei, und sehen Sie wie folgt aus:

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

    }
}

Lassen Sie uns einige der wichtigsten Elemente besprechen.

Zunächst haben wir einige berechnete Eigenschaften hinzugefügt, die wie Ausgänge fungieren (als ob das Fenster in einer STORYBOARD- oder XIB-Datei erstellt wurde):

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

Dadurch erhalten wir Zugriff auf die UI-Elemente, die im Fenster angezeigt werden. Da das Fenster nicht aus einer STORYBOARD- oder XIB-Datei aufgeblasen wird, benötigen wir eine Möglichkeit, es instanziieren zu können (wie wir später in der MainWindowController Klasse sehen). Dies geschieht mit dieser neuen Konstruktormethode:

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

Hier entwerfen wir das Layout des Fensters und platzieren alle UI-Elemente, die zum Erstellen der erforderlichen Benutzeroberfläche erforderlich sind. Bevor wir einem Fenster beliebige UI-Elemente hinzufügen können, muss eine Inhaltsansicht die Elemente enthalten:

ContentView = new NSView (Frame);

Dadurch wird eine Inhaltsansicht erstellt, die das Fenster ausfüllt. Nun fügen wir das erste UI-Element, ein NSButton, zum Fenster hinzu:

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

Im Gegensatz zu iOS verwendet macOS mathematische Notation zum Definieren des Fensterkoordinatensystems. Der Ursprungspunkt befindet sich also in der unteren linken Ecke des Fensters, wobei die Werte rechts und in Richtung der oberen rechten Ecke des Fensters steigen. Wenn wir das neue NSButtonerstellen, berücksichtigen wir dies, während wir seine Position und Größe auf dem Bildschirm definieren.

Die AutoresizingMask = NSViewResizingMask.MinYMargin Eigenschaft teilt der Schaltfläche mit, dass sie an derselben Position vom oberen Rand des Fensters bleibt, wenn die Größe des Fensters vertikal geändert wird. Auch hier ist dies erforderlich, da sich (0,0) unten links im Fenster befindet.

Schließlich wird die ContentView.AddSubview (ClickMeButton)NSButton Methode der Inhaltsansicht hinzugefügt, sodass sie auf dem Bildschirm angezeigt wird, wenn die Anwendung ausgeführt wird und das Fenster angezeigt wird.

Als Nächstes wird dem Fenster eine Bezeichnung hinzugefügt, in der die Anzahl der NSButton Klicks angezeigt wird:

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

Da macOS nicht über ein bestimmtes Bezeichnungs-UI-Element verfügt, haben wir ein speziell formatiertes, nicht bearbeitbares NSTextField Element hinzugefügt, das als Bezeichnung fungiert. Genau wie die Schaltfläche zuvor berücksichtigt die Größe und Position, dass sich (0,0) unten links im Fenster befindet. Die AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin Eigenschaft verwendet den Oder-Operator , um zwei NSViewResizingMask Features zu kombinieren. Dadurch bleibt die Beschriftung an der gleichen Position am oberen Rand des Fensters, wenn die Größe des Fensters vertikal geändert wird, und verkleinert und in der Breite vergrößert wird, während die Größe des Fensters horizontal geändert wird.

Auch hier fügt die ContentView.AddSubview (ClickMeLabel) Methode der NSTextField Inhaltsansicht hinzu, sodass sie beim Ausführen der Anwendung auf dem Bildschirm angezeigt und das Fenster geöffnet wird.

Anpassen des Fenstercontrollers

Da der Entwurf der Datei MainWindow nicht mehr aus einer STORYBOARD- oder XIB-Datei geladen wird, müssen wir einige Anpassungen am Fenstercontroller vornehmen. Bearbeiten Sie die MainWindowController.cs Datei, und sehen Sie wie folgt aus:

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

Lassen Sie uns die wichtigsten Elemente dieser Änderung besprechen.

Zunächst definieren wir eine neue Instanz der MainWindow Klasse und weisen sie der Eigenschaft des Basisfenstercontrollers Window zu:

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

Wir definieren die Position des Bildschirmfensters mit einem CGRect. Genau wie das Koordinatensystem des Fensters definiert der Bildschirm (0,0) als untere linke Ecke. Als Nächstes definieren wir den Stil des Fensters mithilfe des Operators "Or ", um zwei oder mehr NSWindowStyle Features zu kombinieren:

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

Die folgenden NSWindowStyle Features sind verfügbar:

  • Rahmenlos – Das Fenster hat keinen Rahmen.
  • Titel : Das Fenster verfügt über eine Titelleiste.
  • Klonbar - Das Fenster verfügt über eine Schaltfläche zum Schließen und kann geschlossen werden.
  • Miniaturisierbar – Das Fenster verfügt über eine Miniaturgröße-Schaltfläche und kann minimiert werden.
  • Größenänderung – Das Fenster verfügt über eine Schaltfläche zum Ändern der Größe und kann geändert werden.
  • Hilfsprogramm : Das Fenster ist ein Hilfsprogramm-Stilfenster (Panel).
  • DocModal – Wenn es sich bei dem Fenster um ein Panel handelt, handelt es sich um "Document Modal" anstelle von "System Modal".
  • NonactivatingPanel – Wenn es sich bei dem Fenster um ein Panel handelt, wird es nicht zum Standard Fenster gemacht.
  • TexturedBackground – Das Fenster verfügt über einen texturierten Hintergrund.
  • Nicht skaliert – Das Fenster wird nicht skaliert.
  • UnifiedTitleAndToolbar – Der Titel und die Symbolleistenbereiche des Fensters werden verknüpft.
  • Hud - Das Fenster wird als Head-up Display Panel angezeigt.
  • FullScreenWindow – Das Fenster kann in den Vollbildmodus wechseln.
  • FullSizeContentView – Die Inhaltsansicht des Fensters befindet sich hinter dem Titel und dem Symbolleistenbereich.

Die letzten beiden Eigenschaften definieren den Puffertyp für das Fenster und wenn die Zeichnung des Fensters zurückgestellt wird. Weitere Informationen finden NSWindowsSie in der Apple-Dokumentation zur Einführung in Windows .

Da das Fenster nicht aus einer Storyboard- oder XIB-Datei aufgeblasen wird, müssen wir es in unserer MainWindowController.cs simulieren, indem wir die Windows-Methode AwakeFromNib aufrufen:

Window.AwakeFromNib ();

Auf diese Weise können Sie wie ein Standardfenster, das aus einer STORYBOARD- oder XIB-Datei geladen wird, mit Code für das Fenster codieren.

Anzeigen des Fensters

Wenn die STORYBOARD- oder XIB-Datei entfernt wurde und die MainWindow.cs und MainWindowController.cs Dateien geändert wurden, verwenden Sie das Fenster genauso wie jedes normale Fenster, das im Benutzeroberflächen-Generator von Xcode mit einer XIB-Datei erstellt wurde.

Im Folgenden wird eine neue Instanz des Fensters und des zugehörigen Controllers erstellt und das Fenster auf dem Bildschirm angezeigt:

private MainWindowController mainWindowController;
...

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

Wenn die Anwendung ausgeführt wird und die Schaltfläche ein paar Mal geklickt wurde, wird Folgendes angezeigt:

An example app run

Hinzufügen eines Nur-Code-Fensters

Wenn wir nur einen Code hinzufügen möchten, xibless-Fenster zu einer vorhandenen Xamarin.Mac-Anwendung, klicken Sie mit der rechten Maustaste auf das Projekt im Projektmappenblock, und wählen Sie "Neue Datei hinzufügen>".. Wählen Sie im Dialogfeld "Neue Datei" die Option "Xamarin.Mac>Cocoa Window with Controller" aus, wie unten dargestellt:

Adding a new window controller

Genau wie zuvor löschen wir die standardmäßige STORYBOARD- oder XIB-Datei aus dem Projekt (in diesem Fall SecondWindow.xib) und führen die Schritte im Abschnitt "Fenster wechseln" aus, um die Definition des Fensters mit Code zu behandeln .

Hinzufügen eines UI-Elements zu einem Fenster im Code

Ob ein Fenster im Code erstellt oder aus einer Storyboard- oder XIB-Datei geladen wurde, kann es vorkommen, dass wir einem Fenster aus Code ein UI-Element hinzufügen möchten. Zum Beispiel:

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

Der obige Code erstellt ein neues NSButton Element und fügt es zur Fensterinstanz für die MyWindow Anzeige hinzu. Grundsätzlich kann jedes UI-Element, das im Schnittstellen-Generator von Xcode in einer STORYBOARD- oder XIB-Datei definiert werden kann, im Code erstellt und in einem Fenster angezeigt werden.

Definieren der Menüleiste im Code

Aufgrund der aktuellen Einschränkungen in Xamarin.Mac wird nicht empfohlen, dass Sie die MenüleisteNSMenuBar Ihrer Xamarin.Mac-Anwendung in Code erstellen, aber weiterhin die Datei "Main.storyboard" oder "MainMenu.xib" verwenden, um sie zu definieren. Das heißt, Sie können Menüs und Menüelemente im C#-Code hinzufügen und entfernen.

Bearbeiten Sie z. B. die AppDelegate.cs-Datei , und stellen Sie sicher, dass die DidFinishLaunching Methode wie folgt aussieht:

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

Im obigen Code wird ein Statusleistenmenü erstellt und angezeigt, wenn die Anwendung gestartet wird. Weitere Informationen zum Arbeiten mit Menüs finden Sie in unserer Menüdokumentation .

Zusammenfassung

In diesem Artikel wird die Erstellung der Benutzeroberfläche einer Xamarin.Mac-Anwendung im C#-Code im Gegensatz zur Verwendung des Xcode-Schnittstellen-Generators mit .storyboard- oder XIB-Dateien beschrieben.