Windows in Xamarin.Mac

In diesem Artikel wird die Arbeit mit Fenstern und Panels in einer Xamarin.Mac-Anwendung behandelt. Es beschreibt das Erstellen von Fenstern und Panels im Xcode- und Schnittstellen-Generator, das Laden aus Storyboards und XIB-Dateien und die programmgesteuerte Arbeit mit ihnen.

Wenn Sie mit C# und .NET in einer Xamarin.Mac-Anwendung arbeiten, haben Sie Zugriff auf dasselbe Windows und dieselben Panels, in Objective-C denen ein Entwickler arbeitet und Xcode ausführt. Da Xamarin.Mac direkt in Xcode integriert ist, können Sie den Schnittstellen-Generator von Xcode verwenden, um Windows und Panels zu erstellen und zu Standard (oder optional direkt im C#-Code zu erstellen).

Basierend auf ihrem Zweck kann eine Xamarin.Mac-Anwendung ein oder mehrere Windows auf dem Bildschirm präsentieren, um die angezeigten Informationen zu verwalten und zu koordinieren und damit zu arbeiten. Die Hauptfunktionen eines Fensters sind:

  1. Um einen Bereich bereitzustellen, in dem Ansichten und Steuerelemente platziert und verwaltet werden können.
  2. Um Ereignisse als Reaktion auf Benutzerinteraktionen sowohl mit der Tastatur als auch mit der Maus anzunehmen und darauf zu reagieren.

Windows kann in einem Moduslosen Zustand verwendet werden (z. B. ein Text-Editor, der mehrere Dokumente gleichzeitig geöffnet haben kann) oder modal (z. B. ein Dialogfeld "Exportieren", das geschlossen werden muss, bevor die Anwendung fortgesetzt werden kann).

Panels sind eine spezielle Art von Window (eine Unterklasse der Basisklasse NSWindow ), die in der Regel eine Hilfsfunktion in einer Anwendung bedient, z. B. Hilfsfenster wie Textformatinspektoren und Systemfarbauswahl.

Bearbeiten eines Fensters in Xcode

In diesem Artikel werden die Grundlagen der Arbeit mit Windows und Panels in einer Xamarin.Mac-Anwendung behandelt. Es wird dringend empfohlen, dass Sie zuerst den Artikel "Hello, Mac " durcharbeiten, insbesondere die Abschnitte "Einführung in Xcode" und "Interface Builder " und "Outlets" und "Actions ", da es sich um wichtige Konzepte und Techniken handelt, die wir in diesem Artikel verwenden werden.

Möglicherweise möchten Sie sich auch die Verfügbarmachen von C#-Klassen /-Methoden imObjective-CAbschnitt des Xamarin.Mac Internals-Dokuments ansehen, und es werden die befehle Export erläutert, die Register zum Verketten Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.

Einführung in Fenster

Wie oben erwähnt, bietet ein Fenster einen Bereich, in dem Ansichten und Steuerelemente platziert und verwaltet werden können und auf Ereignisse basierend auf Benutzerinteraktionen (entweder über Tastatur oder Maus) reagiert.

Laut Apple gibt es fünf Standard Typen von Windows in einer macOS-App:

  • Dokumentfenster – Ein Dokumentfenster enthält dateibasierte Benutzerdaten wie z. B. eine Kalkulationstabelle oder ein Textdokument.
  • App-Fenster – Ein App-Fenster ist das Standard Fenster einer Anwendung, die nicht dokumentbasiert ist (z. B. die Kalender-App auf einem Mac).
  • Panel – Ein Panel wird über anderen Fenstern schwebt und stellt Tools oder Steuerelemente bereit, mit denen Benutzer arbeiten können, während Dokumente geöffnet sind. In einigen Fällen kann ein Panel transluzent sein (z. B. beim Arbeiten mit großen Grafiken).
  • Dialogfeld – Ein Dialogfeld wird als Reaktion auf eine Benutzeraktion angezeigt und bietet in der Regel Möglichkeiten, wie Benutzer die Aktion ausführen können. Ein Dialogfeld erfordert eine Antwort des Benutzers, bevor es geschlossen werden kann. (Siehe Arbeiten mit Dialogfeldern)
  • Warnungen – Eine Warnung ist ein spezieller Dialogfeldtyp, der angezeigt wird, wenn ein schwerwiegendes Problem auftritt (z. B. ein Fehler) oder als Warnung (z. B. das Vorbereiten des Löschens einer Datei). Da es sich bei einer Warnung um ein Dialogfeld handelt, ist auch eine Benutzerantwort erforderlich, bevor sie geschlossen werden kann. (Siehe Arbeiten mit Warnungen)

Weitere Informationen finden Sie im Abschnitt "Informationen zu Windows" der MacOS-Designdesigns von Apple.

Haupt-, Schlüssel- und inaktive Fenster

Windows in einer Xamarin.Mac-Anwendung kann anders aussehen und verhalten, je nachdem, wie der Benutzer derzeit mit ihnen interagiert. Das wichtigste Dokument- oder App-Fenster, das derzeit den Fokus der Aufmerksamkeit des Benutzers hat, wird als Hauptfenster bezeichnet. In den meisten Fällen ist dieses Fenster auch das Schlüsselfenster (das Fenster, das derzeit Benutzereingaben akzeptiert). Dies ist jedoch nicht immer der Fall, z. B. könnte eine Farbauswahl geöffnet sein und das Schlüsselfenster sein, mit dem der Benutzer interagiert, um den Status eines Elements im Dokumentfenster zu ändern (was weiterhin das Hauptfenster wäre).

Haupt- und Schlüsselfenster (sofern sie getrennt sind) sind immer aktiv, inaktive Windows sind geöffnete Fenster, die sich nicht im Vordergrund befinden. Beispielsweise könnte eine Text-Editor-Anwendung mehrere Dokumente gleichzeitig geöffnet haben, nur das Hauptfenster wäre aktiv, alle anderen wären inaktiv.

Weitere Informationen finden Sie im Abschnitt "Informationen zu Windows" der MacOS-Designdesigns von Apple.

Benennen von Fenstern

Ein Fenster kann eine Titelleiste anzeigen und wenn der Titel angezeigt wird, ist es in der Regel der Name der Anwendung, der Name des Dokuments, an dem gearbeitet wird, oder die Funktion des Fensters (z. B. Inspektor). Einige Anwendungen zeigen keine Titelleiste an, da sie erkennbar sind und nicht mit Dokumenten funktionieren.

Apple schlägt die folgenden Richtlinien vor:

  • Verwenden Sie ihren Anwendungsnamen für den Titel eines Standard-Fensters, das kein Dokument ist.
  • Nennen Sie ein neues Dokumentfenster untitled. Fügen Sie für das erste neue Dokument keine Nummer an den Titel an (z. B untitled 1. ). Wenn der Benutzer vor dem Speichern und Titieren des ersten Dokuments ein weiteres neues Dokument erstellt, rufen Sie dieses Fenster untitled 2, untitled 3usw. auf.

Weitere Informationen finden Sie im Abschnitt "Benennen von Windows" der macOS-Designdesigns von Apple.

Vollbildfenster

In macOS kann das Fenster einer Anwendung im Vollbildmodus alles ausblenden, einschließlich der Anwendungsmenüleiste (die durch Bewegen des Cursors an den oberen Rand des Bildschirms eingeblendet werden kann), um eine ablenkende interaktion mit dem Inhalt zu ermöglichen.

Apple schlägt die folgenden Richtlinien vor:

  • Bestimmen Sie, ob es sinnvoll ist, dass ein Fenster im Vollbildmodus angezeigt wird. Anwendungen, die kurze Interaktionen (z. B. einen Rechner) bereitstellen, sollten keinen Vollbildmodus bereitstellen.
  • Zeigen Sie die Symbolleiste an, wenn die Vollbildaufgabe dies erfordert. In der Regel ist die Symbolleiste ausgeblendet, während sie sich im Vollbildmodus befindet.
  • Das Vollbildfenster sollte alle Features aufweisen, die Benutzer benötigen, um die Aufgabe abzuschließen.
  • Vermeiden Sie nach Möglichkeit die Finder-Interaktion, während sich der Benutzer in einem Vollbildfenster befindet.
  • Nutzen Sie den erweiterten Bildschirmbereich, ohne den Fokus von der Standard Aufgabe zu verschieben.

Weitere Informationen finden Sie im Abschnitt "Windows Im Vollbildmodus" der macOS-Designdesigndesigns von Apple.

Panels

Ein Panel ist ein Hilfsfenster, das Steuerelemente und Optionen enthält, die sich auf das aktive Dokument oder die Auswahl auswirken (z. B. die Systemfarbauswahl):

Ein Farbbereich

Panels können app-spezifisch oder systemweit sein. App-spezifische Panels werden über dem oberen Rand der Dokumentfenster der Anwendung angezeigt und verschwinden, wenn sich die Anwendung im Hintergrund befindet. Systemweite Panels (z. B. der Schriftartenbereich ) werden unabhängig von der Anwendung über allen geöffneten Fenstern schweben.

Apple schlägt die folgenden Richtlinien vor:

  • Im Allgemeinen sollten transparente Panels nur sparsam und grafisch intensiv verwendet werden.
  • Erwägen Sie die Verwendung eines Panels, um Benutzern einfachen Zugriff auf wichtige Steuerelemente oder Informationen zu ermöglichen, die sich direkt auf ihre Aufgabe auswirken.
  • Blenden Sie Panels nach Bedarf aus, und zeigen Sie sie an.
  • Panels sollten immer Titelleisten enthalten.
  • Panels sollten keine aktive Minimierungsschaltfläche enthalten.

Inspektoren

Die meisten modernen macOS-Anwendungen enthalten Hilfssteuerelemente und -optionen, die sich auf das aktive Dokument oder die Auswahl als Inspektoren auswirken, die Teil des Hauptfensters sind (wie die unten gezeigte Seiten-App ), anstatt Panel-Windows zu verwenden:

Beispielprüfung

Weitere Informationen finden Sie im Abschnitt "Panels" der macOS-Designdesigndesigns von Apple.

Erstellen und Standard Beibehalten von Fenstern in Xcode

Wenn Sie eine neue Xamarin.Mac Cocoa-Anwendung erstellen, erhalten Sie standardmäßig ein standardmäßig leeres Fenster. Diese Fenster werden in einer .storyboard Datei definiert, die automatisch im Projekt enthalten ist. Doppelklicken Sie zum Bearbeiten des Fensterentwurfs im Projektmappen-Explorer auf die Main.storyboard Datei:

Auswählen des Standard Storyboards

Dadurch wird das Fensterdesign im Schnittstellen-Generator von Xcode geöffnet:

Bearbeiten der Benutzeroberfläche in Xcode

Im Attributinspektor gibt es mehrere Eigenschaften, mit denen Sie Das Fenster definieren und steuern können:

  • Titel – Dies ist der Text, der in der Titelleiste des Fensters angezeigt wird.
  • AutoSpeichern – Dies ist der Schlüssel , der verwendet wird, um das Fenster zu idieren, wenn es sich um Position und Einstellungen handelt, die automatisch gespeichert werden.
  • Titelleiste – Zeigt das Fenster eine Titelleiste an.
  • Einheitlicher Titel und Symbolleiste – Wenn das Fenster eine Symbolleiste enthält, sollte es Teil der Titelleiste sein.
  • Inhaltsansicht in voller Größe – Ermöglicht die Anzeige des Inhaltsbereichs des Fensters unter der Titelleiste.
  • Schatten – Hat das Fenster einen Schatten.
  • Texturen - Texturfenster können Effekte (z. B. Vibranz) verwenden und durch Ziehen an eine beliebige Stelle im Körper verschoben werden.
  • Schließen – Verfügt das Fenster über eine Schaltfläche zum Schließen.
  • Minimieren – Verfügt das Fenster über eine Schaltfläche zum Minimieren.
  • Ändern der Größe – Verfügt das Fenster über ein Steuerelement zum Ändern der Größe.
  • Symbolleistenschaltfläche – Verfügt das Fenster über eine Schaltfläche zum Ausblenden/Anzeigen der Symbolleiste.
  • Wiederherstellbar – Ist die Position und Einstellungen des Fensters automatisch gespeichert und wiederhergestellt.
  • Beim Start sichtbar – Wird das Fenster automatisch angezeigt, wenn die .xib Datei geladen wird.
  • Beim Deaktivieren ausblenden – Ist das Fenster ausgeblendet, wenn die Anwendung in den Hintergrund wechselt.
  • Beim Schließen freigeben – Wird das Fenster aus dem Arbeitsspeicher gelöscht, wenn es geschlossen wird.
  • QuickInfos immer anzeigen – Werden die QuickInfos ständig angezeigt.
  • Berechnet die Ansichtsschleife neu – Wird die Ansichtsreihenfolge neu berechnet, bevor das Fenster gezeichnet wird.
  • Räume, Exposé und Radfahren – Alle definieren, wie sich das Fenster in diesen macOS-Umgebungen verhält.
  • Vollbild – Bestimmt, ob dieses Fenster in den Vollbildmodus wechseln kann.
  • Animation – Steuert den Für das Fenster verfügbaren Animationstyp.
  • Darstellung – Steuert die Darstellung des Fensters. Für jetzt gibt es nur ein Erscheinungsbild, Aqua.

Weitere Details finden Sie in der Apple-Dokumentation "Einführung in Windows " und "NSWindow ".

Festlegen der Standardgröße und -position

Um die Anfangsposition des Fensters festzulegen und die Größe zu steuern, wechseln Sie zum Größeninspektor:

Die Standardgröße und -position

Von hier aus können Sie die Anfangsgröße des Fensters festlegen, ihm eine minimale und maximale Größe zugeben, die anfängliche Position auf dem Bildschirm festlegen und die Rahmen um das Fenster steuern.

Festlegen eines benutzerdefinierten Standard-Fenstercontrollers

Um Outlets und Aktionen erstellen zu können, um UI-Elemente für C#-Code verfügbar zu machen, muss die Xamarin.Mac-App einen benutzerdefinierten Fenstercontroller verwenden.

Gehen Sie folgendermaßen vor:

  1. Öffnen Sie das Storyboard der App im Schnittstellen-Generator von Xcode.

  2. Wählen Sie das NSWindowController Design-Surface aus.

  3. Wechseln Sie zur Ansicht "Identitätsinspektor", und geben Sie WindowController als Klassenname ein:

    Festlegen des Klassennamens

  4. Speichern Sie Ihre Änderungen, und kehren Sie zum synchronisierenden Visual Studio für Mac zurück.

  5. WindowController.cs In Visual Studio für Mac wird Ihrem Projekt eine Datei im Projektmappen-Explorer hinzugefügt:

    Auswählen des Windows-Controllers

  6. Öffnen Sie das Storyboard im Schnittstellen-Generator von Xcode erneut.

  7. Die WindowController.h Datei steht zur Verwendung zur Verfügung:

    Bearbeiten der Datei

Hinzufügen von UI-Elementen

Um den Inhalt eines Fensters zu definieren, ziehen Sie Steuerelemente aus dem Bibliotheksinspektor auf den Schnittstellen-Editor. Weitere Informationen zur Verwendung des Schnittstellen-Generators zum Erstellen und Aktivieren von Steuerelementen finden Sie in unserer Dokumentation zur Einführung in Xcode und Schnittstellen-Generator .

Als Beispiel ziehen wir eine Symbolleiste aus dem Bibliotheksinspektor in das Fenster im Schnittstellen-Editor:

Auswählen einer Symbolleiste aus der Bibliothek

Ziehen Sie als Nächstes in eine Textansicht , und skalieren Sie ihn, um den Bereich unter der Symbolleiste auszufüllen:

Hinzufügen einer Textansicht

Da die Textansicht verkleinern und wachsen soll, während sich die Größe des Fensters ändert, wechseln wir zum Einschränkungs-Editor , und fügen Sie die folgenden Einschränkungen hinzu:

Bearbeitungseinschränkungen

Wenn Sie oben im Editor auf die vier roten I-Balken klicken und auf "4 Einschränkungen hinzufügen" klicken, teilen wir der Textansicht mit, dass sie sich an den angegebenen X,Y-Koordinaten halten und horizontal und vertikal verkleinern, während die Größe des Fensters geändert wird.

Machen Sie schließlich die Textansicht mit einem Outlet für Code verfügbar (stellen Sie sicher, dass Sie die ViewController.h Datei auswählen):

Konfigurieren einer Steckdose

Speichern Sie Ihre Änderungen, und wechseln Sie zurück zu Visual Studio für Mac, um mit Xcode zu synchronisieren.

Weitere Informationen zum Arbeiten mit Outlets und Aktionen finden Sie in unserer Outlet- und Action-Dokumentation.

Standardfensterworkflow

Für jedes Fenster, mit dem Sie in Ihrer Xamarin.Mac-Anwendung arbeiten, ist der Prozess im Grunde identisch mit dem, was wir gerade oben gemacht haben:

  1. Fügen Sie für neue Fenster, die dem Projekt nicht automatisch hinzugefügt werden, eine neue Fensterdefinition zum Projekt hinzu. Dies wird im Folgenden ausführlich erläutert.
  2. Doppelklicken Sie auf die Main.storyboard Datei, um das Fensterdesign zur Bearbeitung im Benutzeroberflächen-Generator von Xcode zu öffnen.
  3. Ziehen Sie ein neues Fenster in das Design der Benutzeroberfläche, und verbinden Sie das Fenster mithilfe von Segues in das Hauptfenster (weitere Informationen finden Sie im Abschnitt "Segues" unserer Dokumentation "Arbeiten mit Storyboards").
  4. Legen Sie alle erforderlichen Fenstereigenschaften im Attributinspektor und im Größeninspektor fest.
  5. Ziehen Sie das Shape in die Steuerelemente, die zum Erstellen der Benutzeroberfläche erforderlich sind, und konfigurieren Sie sie im Attributinspektor.
  6. Verwenden Sie den Größeninspektor , um die Größenänderung für Ihre UI-Elemente zu behandeln.
  7. Machen Sie die UI-Elemente des Fensters über Outlets und Aktionen für C#-Code verfügbar.
  8. Speichern Sie Ihre Änderungen, und wechseln Sie zurück zu Visual Studio für Mac, um mit Xcode zu synchronisieren.

Nachdem wir nun ein einfaches Fenster erstellt haben, werden wir uns die typischen Prozesse ansehen, die eine Xamarin.Mac-Anwendung beim Arbeiten mit Fenstern ausführt.

Anzeigen des Standardfensters

Standardmäßig zeigt eine neue Xamarin.Mac-Anwendung automatisch das Fenster an, das beim Starten in der MainWindow.xib Datei definiert ist:

Beispielfenster, das ausgeführt wird

Da wir den Entwurf dieses Fensters oben geändert haben, enthält es jetzt ein Standardmäßiges Symbolleisten- und Textansichtssteuerelement . Der folgende Abschnitt in der Datei ist für die Info.plist Anzeige dieses Fensters verantwortlich:

Bearbeiten von Info.plist

Das Dropdownmenü "Hauptschnittstelle" wird verwendet, um das Storyboard auszuwählen, das als Standard App-UI (in diesem FallMain.storyboard) verwendet wird.

Dem Projekt wird automatisch ein Ansichtscontroller hinzugefügt, um das angezeigte Hauptfenster (zusammen mit der primären Ansicht) zu steuern. Sie wird in der ViewController.cs Datei definiert und dem Besitzer der Datei im Schnittstellen-Generator unter dem Identitätsinspektor angefügt:

Festlegen des Besitzers der Datei

Für unser Fenster möchten wir, dass es beim ersten Öffnen einen Titel untitled hat, damit wir die Methode in der ViewWillAppearViewController.cs folgenden Abbildung überschreiben:

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

    // Set Window Title
    this.View.Window.Title = "untitled";
}

Hinweis

Die Eigenschaft des Fensters Title wird in der ViewWillAppear Methode anstelle der ViewDidLoad Methode festgelegt, da die Ansicht zwar in den Arbeitsspeicher geladen wird, aber noch nicht vollständig instanziiert wird. Der Zugriff auf die Title Eigenschaft in der ViewDidLoad Methode wird eine null Ausnahme erhalten, da das Fenster noch nicht erstellt und mit der Eigenschaft verkabelt wurde.

Programmgesteuertes Schließen eines Fensters

Es kann vorkommen, dass Sie ein Fenster programmgesteuert in einer Xamarin.Mac-Anwendung schließen möchten, außer dass der Benutzer auf die Schaltfläche "Schließen" des Fensters oder ein Menüelement klickt. macOS bietet zwei verschiedene Möglichkeiten zum programmgesteuerten Schließen eines NSWindow Programms: PerformClose und Close.

PerformClose

Durch Aufrufen der PerformClose Methode eines Elements NSWindow wird simuliert, dass der Benutzer auf die Schaltfläche "Schließen" des Fensters klickt, indem er die Schaltfläche im Moment hervorhebt und dann das Fenster schließt.

Wenn die Anwendung das NSWindowWillClose Ereignis implementiert, wird es ausgelöst, bevor das Fenster geschlossen wird. Wenn das Ereignis zurückgegeben falsewird, wird das Fenster nicht geschlossen. Wenn das Fenster nicht über eine Schaltfläche "Schließen " verfügt oder aus irgendeinem Grund nicht geschlossen werden kann, gibt das Betriebssystem den Benachrichtigungssound aus.

Zum Beispiel:

MyWindow.PerformClose(this);

Würde versuchen, die MyWindowNSWindow Instanz zu schließen. Wenn dies erfolgreich war, wird das Fenster geschlossen, andernfalls wird der Benachrichtigungssound ausgegeben und bleibt geöffnet.

Schließen

Wenn Sie die Close Methode einer Methode aufrufenNSWindow, wird der Benutzer nicht simuliert, auf die Schaltfläche "Schließen" des Fensters zu klicken, indem er die Schaltfläche im Moment hervorhebt, das Fenster wird einfach geschlossen.

Ein Fenster muss nicht sichtbar sein, um geschlossen zu werden, und eine NSWindowWillCloseNotification Benachrichtigung wird für das geschlossene Fenster im Standardbenachrichtigungscenter veröffentlicht.

Die Close Methode unterscheidet sich auf zwei wichtige Arten von der PerformClose Methode:

  1. Es wird nicht versucht, das WillClose Ereignis auszuheben.
  2. Es simuliert nicht, dass der Benutzer auf die Schaltfläche "Schließen " klickt, indem er die Schaltfläche im Moment hervorhebung.

Zum Beispiel:

MyWindow.Close();

Würde die MyWindowNSWindow Instanz schließen.

Geänderter Fensterinhalt

In macOS hat Apple eine Möglichkeit bereitgestellt, den Benutzer darüber zu informieren, dass der Inhalt eines Fensters (NSWindow) vom Benutzer geändert wurde und gespeichert werden muss. Wenn das Fenster geänderten Inhalt enthält, wird ein kleiner schwarzer Punkt im "Schließen"-Widget angezeigt:

Ein Fenster mit der geänderten Markierung

Wenn der Benutzer versucht, das Fenster zu schließen oder die Mac-App zu beenden, während nicht gespeicherte Änderungen am Inhalt des Fensters vorhanden sind, sollten Sie ein Dialogfeld oder ein modales Blatt präsentieren und dem Benutzer erlauben, seine Änderungen zuerst zu speichern:

Beim Schließen des Fensters wird ein Speicherblatt angezeigt.

Markieren eines Fensters als geändert

Verwenden Sie den folgenden Code, um ein Fenster als geänderten Inhalt zu markieren:

// Mark Window content as modified
Window.DocumentEdited = true;

Und nachdem die Änderung gespeichert wurde, löschen Sie das geänderte Flag mit:

// Mark Window content as not modified
Window.DocumentEdited = false;

Speichern von Änderungen vor dem Schließen eines Fensters

Um zu beobachten, ob der Benutzer ein Fenster schließt und ihm das Speichern von geänderten Inhalten im Voraus zulässt, müssen Sie eine Unterklasse von NSWindowDelegate und überschreiben deren WindowShouldClose Methode. Zum Beispiel:

using System;
using AppKit;
using System.IO;
using Foundation;

namespace SourceWriter
{
    public class EditorWindowDelegate : NSWindowDelegate
    {
        #region Computed Properties
        public NSWindow Window { get; set;}
        #endregion

        #region constructors
        public EditorWindowDelegate (NSWindow window)
        {
            // Initialize
            this.Window = window;

        }
        #endregion

        #region Override Methods
        public override bool WindowShouldClose (Foundation.NSObject sender)
        {
            // is the window dirty?
            if (Window.DocumentEdited) {
                var alert = new NSAlert () {
                    AlertStyle = NSAlertStyle.Critical,
                    InformativeText = "Save changes to document before closing window?",
                    MessageText = "Save Document",
                };
                alert.AddButton ("Save");
                alert.AddButton ("Lose Changes");
                alert.AddButton ("Cancel");
                var result = alert.RunSheetModal (Window);

                // Take action based on result
                switch (result) {
                case 1000:
                    // Grab controller
                    var viewController = Window.ContentViewController as ViewController;

                    // Already saved?
                    if (Window.RepresentedUrl != null) {
                        var path = Window.RepresentedUrl.Path;

                        // Save changes to file
                        File.WriteAllText (path, viewController.Text);
                        return true;
                    } else {
                        var dlg = new NSSavePanel ();
                        dlg.Title = "Save Document";
                        dlg.BeginSheet (Window, (rslt) => {
                            // File selected?
                            if (rslt == 1) {
                                var path = dlg.Url.Path;
                                File.WriteAllText (path, viewController.Text);
                                Window.DocumentEdited = false;
                                viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
                                viewController.View.Window.RepresentedUrl = dlg.Url;
                                Window.Close();
                            }
                        });
                        return true;
                    }
                    return false;
                case 1001:
                    // Lose Changes
                    return true;
                case 1002:
                    // Cancel
                    return false;
                }
            }

            return true;
        }
        #endregion
    }
}

Verwenden Sie den folgenden Code, um eine Instanz dieses Delegaten an das Fenster anzufügen:

// Set delegate
Window.Delegate = new EditorWindowDelegate(Window);

Speichern von Änderungen vor dem Schließen der App

Schließlich sollte Ihre Xamarin.Mac-App überprüfen, ob einer seiner Windows-Inhalte geänderten Inhalt enthält, und dem Benutzer das Speichern der Änderungen vor dem Beenden gestatten. Bearbeiten Sie dazu Die AppDelegate.cs Datei, überschreiben Sie die ApplicationShouldTerminate Methode, und stellen Sie sicher, dass sie wie folgt aussieht:

public override NSApplicationTerminateReply ApplicationShouldTerminate (NSApplication sender)
{
    // See if any window needs to be saved first
    foreach (NSWindow window in NSApplication.SharedApplication.Windows) {
        if (window.Delegate != null && !window.Delegate.WindowShouldClose (this)) {
            // Did the window terminate the close?
            return NSApplicationTerminateReply.Cancel;
        }
    }

    // Allow normal termination
    return NSApplicationTerminateReply.Now;
}

Arbeiten mit mehreren Fenstern

Die meisten dokumentbasierten Mac-Anwendungen können mehrere Dokumente gleichzeitig bearbeiten. Ein Text-Editor kann z. B. mehrere Textdateien gleichzeitig zur Bearbeitung öffnen. Standardmäßig verfügt eine neue Xamarin.Mac-Anwendung über ein Menü "Datei ", bei dem ein neues Element automatisch mit der newDocument:Aktion verkabelt wird.

Der folgende Code aktiviert dieses neue Element und ermöglicht es dem Benutzer, mehrere Kopien des Hauptfensters zu öffnen, um mehrere Dokumente gleichzeitig zu bearbeiten.

Bearbeiten Sie die AppDelegate.cs Datei, und fügen Sie die folgende berechnete Eigenschaft hinzu:

public int UntitledWindowCount { get; set;} =1;

Verwenden Sie dies, um die Anzahl der nicht gespeicherten Dateien nachzuverfolgen, damit wir dem Benutzer Feedback geben können (gemäß den Richtlinien von Apple wie oben beschrieben).

Fügen Sie als Nächstes die folgende Methode hinzu:

[Export ("newDocument:")]
void NewDocument (NSObject sender) {
    // Get new window
    var storyboard = NSStoryboard.FromName ("Main", null);
    var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

    // Display
    controller.ShowWindow(this);

    // Set the title
    controller.Window.Title = (++UntitledWindowCount == 1) ? "untitled" : string.Format ("untitled {0}", UntitledWindowCount);
}

Dieser Code erstellt eine neue Version unseres Fenstercontrollers, lädt das neue Fenster, macht es zum Haupt- und Schlüsselfenster und legt ihn zum Titel fest. Wenn wir nun unsere Anwendung ausführen und im Menü "Datei" die Option "Neu" auswählen, wird ein neues Editorfenster geöffnet und angezeigt:

Ein neues unbenanntes Fenster wurde hinzugefügt.

Wenn wir das Windows-Menü öffnen, können Sie sehen, dass die Anwendung automatisch unsere geöffneten Fenster nachverfolgt und verarbeitet:

Das Fenstermenü

Weitere Informationen zum Arbeiten mit Menüs in einer Xamarin.Mac-Anwendung finden Sie in unserer Dokumentation zum Arbeiten mit Menüs .

Abrufen des aktuell aktiven Fensters

In einer Xamarin.Mac-Anwendung, die mehrere Fenster (Dokumente) öffnen kann, gibt es Zeiten, in denen Sie das aktuelle, oberste Fenster (das Schlüsselfenster) abrufen müssen. Der folgende Code gibt das Schlüsselfenster zurück:

var window = NSApplication.SharedApplication.KeyWindow;

Sie kann in einer beliebigen Klasse oder Methode aufgerufen werden, die auf das aktuelle Schlüsselfenster zugreifen muss. Wenn derzeit kein Fenster geöffnet ist, wird es zurückgegeben null.

Zugreifen auf alle App-Fenster

Es kann vorkommen, dass Sie auf alle Fenster zugreifen müssen, die Ihre Xamarin.Mac-App derzeit geöffnet hat. Um beispielsweise festzustellen, ob eine Datei, die der Benutzer öffnen möchte, bereits in einem beendenden Fenster geöffnet ist.

Die NSApplication.SharedApplication Standard enthält eine Windows Eigenschaft, die ein Array aller geöffneten Fenster in Ihrer App enthält. Sie können dieses Array durchlaufen, um auf alle aktuellen Fenster der App zuzugreifen. Zum Beispiel:

// Is the file already open?
for(int n=0; n<NSApplication.SharedApplication.Windows.Length; ++n) {
    var content = NSApplication.SharedApplication.Windows[n].ContentViewController as ViewController;
    if (content != null && path == content.FilePath) {
        // Bring window to front
        NSApplication.SharedApplication.Windows[n].MakeKeyAndOrderFront(this);
        return true;
    }
}

Im Beispielcode werden jedes zurückgegebene Fenster in die benutzerdefinierte Klasse in unserer App umgewandelt und der Wert einer benutzerdefinierten ViewControllerPath Eigenschaft anhand des Pfads einer Datei getestet, die der Benutzer öffnen möchte. Wenn die Datei bereits geöffnet ist, bringen wir dieses Fenster in den Vordergrund.

Anpassen der Fenstergröße im Code

Es gibt Zeiten, in denen die Anwendung die Größe eines Fensters im Code ändern muss. Zum Ändern der Größe und Neupositionierung eines Fensters passen Sie die Eigenschaft an Frame . Beim Anpassen der Größe eines Fensters müssen Sie in der Regel auch den Ursprung anpassen, damit das Fenster aufgrund des Koordinatensystems von macOS an derselben Position bleibt.

Im Gegensatz zu iOS, in dem die obere linke Ecke steht (0,0), verwendet macOS ein mathematisches Koordinatensystem, in dem die untere linke Ecke des Bildschirms steht (0,0). In iOS erhöhen sich die Koordinaten, während Sie nach unten nach rechts navigieren. In macOS erhöhen sich die Koordinaten nach oben nach rechts.

Im folgenden Beispielcode wird die Größe eines Fensters geändert:

nfloat y = 0;

// Calculate new origin
y = Frame.Y - (768 - Frame.Height);

// Resize and position window
CGRect frame = new CGRect (Frame.X, y, 1024, 768);
SetFrame (frame, true);

Wichtig

Wenn Sie eine Fenstergröße und -position im Code anpassen, müssen Sie sicherstellen, dass Sie die mindesten und maximalen Größen berücksichtigen, die Sie im Schnittstellen-Generator festgelegt haben. Dies wird nicht automatisch berücksichtigt, und Sie können das Fenster größer oder kleiner machen als diese Grenzwerte.

Überwachen von Fenstergrößenänderungen

Es kann vorkommen, dass Sie Änderungen an der Größe eines Fensters in Ihrer Xamarin.Mac-App überwachen müssen. Um z. B. Inhalte neu zu zeichnen, um die neue Größe anzupassen.

Um Größenänderungen zu überwachen, stellen Sie zunächst sicher, dass Sie dem Fenstercontroller im Schnittstellen-Generator von Xcode eine benutzerdefinierte Klasse zugewiesen haben. Beispiel: MasterWindowController

Der Identitätsinspektor

Bearbeiten Sie als Nächstes die benutzerdefinierte Window Controller-Klasse, und überwachen Sie das DidResize Ereignis im Fenster des Controllers, um über Änderungen der Livegröße benachrichtigt zu werden. Zum Beispiel:

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

    Window.DidResize += (sender, e) => {
        // Do something as the window is being live resized
    };
}

Optional können Sie das DidEndLiveResize Ereignis verwenden, um nur benachrichtigt zu werden, nachdem der Benutzer die Änderung der Fenstergröße abgeschlossen hat. Beispiel:

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

        Window.DidEndLiveResize += (sender, e) => {
        // Do something after the user's finished resizing
        // the window
    };
}

Festlegen des Titels und der dargestellten Datei eines Fensters

Wenn Sie mit Fenstern arbeiten, die Dokumente darstellen, weist eine DocumentEdited Eigenschaft auf, die festgelegt ist, NSWindow dass true ein kleiner Punkt in der Schaltfläche "Schließen" angezeigt wird, um dem Benutzer einen Hinweis darauf zu geben, dass die Datei geändert wurde und vor dem Schließen gespeichert werden soll.

Lassen Sie uns unsere ViewController.cs Datei bearbeiten und die folgenden Änderungen vornehmen:

public bool DocumentEdited {
    get { return View.Window.DocumentEdited; }
    set { View.Window.DocumentEdited = value; }
}
...

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

    // Set Window Title
    this.View.Window.Title = "untitled";

    View.Window.WillClose += (sender, e) => {
        // is the window dirty?
        if (DocumentEdited) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to give the user the ability to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        }
    };
}

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

    // Show when the document is edited
    DocumentEditor.TextDidChange += (sender, e) => {
        // Mark the document as dirty
        DocumentEdited = true;
    };

    // Overriding this delegate is required to monitor the TextDidChange event
    DocumentEditor.ShouldChangeTextInRanges += (NSTextView view, NSValue[] values, string[] replacements) => {
        return true;
    };

}

Außerdem überwachen wir das WillClose Ereignis im Fenster und überprüfen den Status der DocumentEdited Eigenschaft. Wenn es erforderlich ist true , dem Benutzer die Möglichkeit zu geben, die Änderungen in der Datei zu speichern. Wenn wir unsere App ausführen und Text eingeben, wird der Punkt angezeigt:

Ein geändertes Fenster

Wenn Sie versuchen, das Fenster zu schließen, erhalten Sie eine Benachrichtigung:

Anzeigen eines Speicherdialogfelds

Wenn Sie ein Dokument aus einer Datei laden, legen Sie den Titel des Fensters mithilfe der window.SetTitleWithRepresentedFilename (Path.GetFileName(path)); Methode auf den Namen der Datei fest (vorausgesetzt, es handelt sich um eine Zeichenfolge, path die die geöffnete Datei darstellt). Darüber hinaus können Sie die URL der Datei mithilfe der window.RepresentedUrl = url; Methode festlegen.

Wenn die URL auf einen dateityp zeigt, der vom Betriebssystem bekannt ist, wird das Symbol in der Titelleiste angezeigt. Wenn der Benutzer mit der rechten Maustaste auf das Symbol klickt, wird der Pfad zur Datei angezeigt.

Bearbeiten Sie die AppDelegate.cs Datei, und fügen Sie die folgende Methode hinzu:

[Export ("openDocument:")]
void OpenDialog (NSObject sender)
{
    var dlg = NSOpenPanel.OpenPanel;
    dlg.CanChooseFiles = true;
    dlg.CanChooseDirectories = false;

    if (dlg.RunModal () == 1) {
        // Nab the first file
        var url = dlg.Urls [0];

        if (url != null) {
            var path = url.Path;

            // Get new window
            var storyboard = NSStoryboard.FromName ("Main", null);
            var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

            // Display
            controller.ShowWindow(this);

            // Load the text into the window
            var viewController = controller.Window.ContentViewController as ViewController;
            viewController.Text = File.ReadAllText(path);
                    viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
            viewController.View.Window.RepresentedUrl = url;

        }
    }
}

Wenn wir nun unsere App ausführen, wählen Sie im Menü "Datei" die Option "Öffnen" aus, wählen Sie im Dialogfeld "Öffnen" eine Textdatei aus, und öffnen Sie sie:

Ein geöffnetes Dialogfeld

Die Datei wird angezeigt, und der Titel wird mit dem Symbol der Datei festgelegt:

Der Inhalt einer geladenen Datei

Hinzufügen eines neuen Fensters zu einem Projekt

Neben dem Standard Dokumentfenster muss möglicherweise eine Xamarin.Mac-Anwendung dem Benutzer andere Fenstertypen anzeigen, z. B. Einstellungen oder Inspektorbereiche.

Gehen Sie wie folgt vor, um ein neues Fenster hinzuzufügen:

  1. Doppelklicken Sie im Projektmappen-Explorer auf die Main.storyboard Datei, um sie zum Bearbeiten im Schnittstellen-Generator von Xcode zu öffnen.

  2. Ziehen Sie einen neuen Fenstercontroller aus der Bibliothek , und legen Sie ihn auf der Entwurfsoberfläche ab:

    Auswählen eines neuen Fenstercontrollers in der Bibliothek

  3. Geben Sie im Identitätsinspektor die Storyboard-IDPreferencesWindow ein:

    Festlegen der Storyboard-ID

  4. Entwerfen Sie Ihre Benutzeroberfläche:

    Entwerfen der Benutzeroberfläche

  5. Öffnen Sie das App-Menü (MacWindows), wählen Sie "Einstellungen" aus ..., klicken Sie mit gedrückter CTRL-TASTE, und ziehen Sie es in das neue Fenster:

    Erstellen eines Segue

  6. Wählen Sie im Popupmenü "Anzeigen" aus.

  7. Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um mit Xcode zu synchronisieren.

Wenn wir den Code ausführen und im Anwendungsmenü die Einstellungenauswählen, wird das Fenster angezeigt:

Beispielmenü

Arbeiten mit Panels

Wie zu Beginn dieses Artikels erwähnt, wird ein Panel über anderen Fenstern angezeigt und stellt Tools oder Steuerelemente bereit, mit denen Benutzer arbeiten können, während Dokumente geöffnet sind.

Genau wie jeder andere Fenstertyp, mit dem Sie in Ihrer Xamarin.Mac-Anwendung arbeiten, ist der Prozess im Grunde identisch:

  1. Fügen Sie dem Projekt eine neue Fensterdefinition hinzu.
  2. Doppelklicken Sie auf die .xib Datei, um das Fensterdesign zur Bearbeitung im Benutzeroberflächen-Generator von Xcode zu öffnen.
  3. Legen Sie alle erforderlichen Fenstereigenschaften im Attributinspektor und im Größeninspektor fest.
  4. Ziehen Sie das Shape in die Steuerelemente, die zum Erstellen der Benutzeroberfläche erforderlich sind, und konfigurieren Sie sie im Attributinspektor.
  5. Verwenden Sie den Größeninspektor , um die Größenänderung für Ihre UI-Elemente zu behandeln.
  6. Machen Sie die UI-Elemente des Fensters über Outlets und Aktionen für C#-Code verfügbar.
  7. Speichern Sie Ihre Änderungen, und wechseln Sie zurück zu Visual Studio für Mac, um mit Xcode zu synchronisieren.

Im Attributinspektor haben Sie die folgenden Speziellen Optionen für Panels:

Der Attributinspektor

  • Formatvorlage – Ermöglicht Ihnen das Anpassen der Formatvorlage des Panels von: Regulärer Bereich (sieht wie ein Standardfenster aus), Hilfsprogrammbereich (hat eine kleinere Titelleiste), HUD-Panel (ist transluzent und die Titelleiste ist Teil des Hintergrunds).
  • Nicht aktivieren – Bestimmt im Bereich wird zum Schlüsselfenster.
  • Dokument modal – Wenn Dokument modal , wird der Bereich nur über den Fenstern der Anwendung schweben, sonst wird es vor allem schweben.

Gehen Sie wie folgt vor, um einen neuen Bereich hinzuzufügen:

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie "Neue Datei hinzufügen>" aus.

  2. Wählen Sie im Dialogfeld "Neue Datei" die Option "Xamarin.Mac>Cocoa Window" mit Controller aus:

    Hinzufügen eines neuen Fenstercontrollers

  3. Geben Sie für den NamenDocumentPanel ein, und klicken Sie auf Neu.

  4. Doppelklicken Sie auf die DocumentPanel.xib Datei, um sie zum Bearbeiten im Schnittstellen-Generator zu öffnen:

    Bearbeiten des Bereichs

  5. Löschen Sie das vorhandene Fenster, und ziehen Sie einen Bereich aus dem Bibliotheksinspektor im Schnittstellen-Editor:

    Löschen des vorhandenen Fensters

  6. Verbinden Sie den Bereich mit dem Fenster "Besitzer - " - der Datei:

    Ziehen, um das Panel zu verdrahten

  7. Wechseln Sie zum Identitätsinspektor, und legen Sie die Klasse des Panels auf :DocumentPanel

    Festlegen der Klasse des Panels

  8. Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um mit Xcode zu synchronisieren.

  9. Bearbeiten Sie die DocumentPanel.cs Datei, und ändern Sie die Klassendefinition wie folgt:

    public partial class DocumentPanel : NSPanel

  10. Speichern Sie die Änderungen in der Datei.

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

public override void DidFinishLaunching (NSNotification notification)
{
        // Display panel
    var panel = new DocumentPanelController ();
    panel.Window.MakeKeyAndOrderFront (this);
}

Wenn wir unsere Anwendung ausführen, wird das Panel angezeigt:

Der Bereich in einer ausgeführten App

Wichtig

Panel-Windows wurde von Apple veraltet und sollte durch Inspektorschnittstellen ersetzt werden.

Zusammenfassung

Dieser Artikel hat einen detaillierten Blick auf die Arbeit mit Windows und Panels in einer Xamarin.Mac-Anwendung gemacht. Wir haben die verschiedenen Typen und Verwendungen von Windows und Panels gesehen, wie Sie Windows und Panels im Schnittstellen-Generator von Xcode erstellen und Standard und wie Sie mit Windows und Panels in C#-Code arbeiten.