Windows in Xamarin.Mac

In diesem Artikel wird das Arbeiten mit Fenstern und Bereichen in einer Xamarin.Mac-Anwendung behandelt. Es beschreibt das Erstellen von Fenstern und Bereichen in Xcode und Interface Builder, das Laden aus Storyboards und XIB-Dateien und das programmgesteuerte Arbeiten mit ihnen.

Wenn Sie mit C# und .NET in einer Xamarin.Mac-Anwendung arbeiten, haben Sie Zugriff auf die gleichen Windows- und Panels wie ein Entwickler, der in Objective-C arbeitet, und auf Xcode . Da Xamarin.Mac direkt in Xcode integriert wird, können Sie den Schnittstellen-Generator von Xcode verwenden, um Ihre Windows- und Panels zu erstellen und zu verwalten (oder optional direkt in C#-Code zu erstellen).

Basierend auf ihrem Zweck kann eine Xamarin.Mac-Anwendung ein oder mehrere Windows auf dem Bildschirm anzeigen, um die angezeigten und mit ihr verbundenen Informationen zu verwalten und zu koordinieren. Die wichtigsten Funktionen eines Fensters sind:

  1. Bereitstellen eines Bereichs, 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 zu akzeptieren und darauf zu reagieren.

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

Panels sind eine spezielle Art von Fenster (eine Unterklasse der Basisklasse NSWindow ), die in der Regel eine Hilfsfunktion in einer Anwendung wie Hilfsfenster wie Textformatinspektoren und Systemfarbauswahl erfüllen.

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 Aktionen , da er wichtige Konzepte und Techniken behandelt, die wir in diesem Artikel verwenden werden.

Möglicherweise sollten Sie auch einen Blick auf den Abschnitt Verfügbarmachen von C#-Klassen/-Methoden für Objective-C das Xamarin.Mac Internals-Dokument werfen. Darin werden die Befehle und Export erläutert, die Register zum Verknüpfen Ihrer C#-Klassen mit Objective-C Objekten und UI-Elementen verwendet werden.

Einführung in Windows

Wie bereits erwähnt, stellt ein Fenster einen Bereich bereit, 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 Arten von Windows in einer macOS-App:

  • Dokumentfenster : Ein Dokumentfenster enthält dateibasierte Benutzerdaten, z. B. eine Tabelle 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 Bereich schwebt über anderen Fenstern 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. bei der Arbeit 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 abschließen können. Ein Dialogfeld erfordert eine Antwort des Benutzers, bevor er geschlossen werden kann. (Siehe Arbeiten mit Dialogfeldern)
  • Warnungen : Eine Warnung ist ein spezieller Dialogtyp, der angezeigt wird, wenn ein schwerwiegendes Problem (z. B. ein Fehler) oder eine Warnung (z. B. die Vorbereitung zum Löschen einer Datei) auftritt. 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 Über Windows der macOS-Designdesigns von Apple.

Haupt-, Schlüssel- und inaktive Fenster

Windows in einer Xamarin.Mac-Anwendung kann je nachdem, wie der Benutzer derzeit mit ihnen interagiert, unterschiedlich aussehen und sich verhalten. Das wichtigste Dokument- oder App-Fenster, das sich derzeit im Fokus der Aufmerksamkeit des Benutzers befindet, 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. kann eine Farbauswahl geöffnet sein und das Schlüsselfenster sein, mit dem der Benutzer interagiert, um den Status eines Elements im Dokumentfenster zu ändern (das immer noch das Hauptfenster wäre).

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

Weitere Informationen finden Sie im Abschnitt Über Windows der macOS-Designdesigns von Apple.

Benennen von Fenstern

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

Apple schlägt die folgenden Richtlinien vor:

  • Verwenden Sie den Anwendungsnamen für den Titel eines Standard,nicht aus Dokument stammenden Fensters.
  • Geben Sie einem neuen Dokumentfenster untitledden Namen . Fügen Sie für das erste neue Dokument keine Zahl an den Titel an (z untitled 1. B. ). Wenn der Benutzer vor dem Speichern und Titieren des ersten Dokuments ein anderes neues Dokument erstellt, rufen Sie dieses Fenster untitled 2, untitled 3usw. auf.

Weitere Informationen finden Sie im Abschnitt Benennen von Windows in den macOS-Designdesigns von Apple.

Vollbildfenster

Unter macOS kann das Fenster einer Anwendung im Vollbildmodus alles ausblenden, einschließlich der Anwendungsmenüleiste (die durch Bewegen des Cursors an den oberen Bildschirmrand angezeigt werden kann), um eine ablenkungsfreie Interaktion mit dem Inhalt zu ermöglichen.

Apple schlägt die folgenden Richtlinien vor:

  • Ermitteln Sie, ob es sinnvoll ist, dass ein Fenster im Vollbildmodus angezeigt wird. Anwendungen, die kurze Interaktionen bereitstellen (z. B. ein Rechner), sollten keinen Vollbildmodus bereitstellen.
  • Zeigen Sie die Symbolleiste an, wenn dies für die Vollbildaufgabe erforderlich ist. In der Regel ist die Symbolleiste im Vollbildmodus ausgeblendet.
  • Das Vollbildfenster sollte über alle Features verfügen, die Benutzer zum Ausführen der Aufgabe benötigen.
  • Vermeiden Sie nach Möglichkeit finder-Interaktionen, während sich der Benutzer in einem Vollbildfenster befindet.
  • Nutzen Sie den erweiterten Bildschirmraum, ohne den Fokus von der Standard Aufgabe zu verschieben.

Weitere Informationen finden Sie im Abschnitt Vollbildfenster der macOS-Designdesigns von Apple.

Panels

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

Ein Farbbereich

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

Apple schlägt die folgenden Richtlinien vor:

  • Verwenden Sie im Allgemeinen ein Standardpanel, transparente Panels sollten nur sparsam und für grafisch intensive Aufgaben verwendet werden.
  • Erwägen Sie die Verwendung eines Bereichs, um Benutzern einfachen Zugriff auf wichtige Steuerelemente oder Informationen zu gewähren, die sich direkt auf ihre Aufgabe auswirken.
  • Blenden Sie Bereiche nach Bedarf aus, und zeigen Sie sie an.
  • Panels sollten immer die Titelleiste enthalten.
  • Panels sollten keine aktive Schaltfläche zum Minimieren enthalten.

Inspectors

Die meisten modernen macOS-Anwendungen bieten zusätzliche Steuerelemente und Optionen, die sich auf das aktive Dokument oder die Auswahl auswirken, als Inspektoren , die Teil des Hauptfensters sind (wie die unten gezeigte Seiten-App ), anstatt Panelfenster zu verwenden:

Beispielinspektor

Weitere Informationen finden Sie im Abschnitt Panels der macOS-Designdesigns von Apple und in unserer MacInspector-Beispiel-App für eine vollständige Implementierung einer Inspektorschnittstelle in einer Xamarin.Mac-App.

Erstellen und Verwalten von Fenstern in Xcode

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

Auswählen des Standard Storyboards

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

Bearbeiten der Benutzeroberfläche in Xcode

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

  • Titel : Dies ist der Text, der in der Titelleiste des Fensters angezeigt wird.
  • Automatisches Speichern : Dies ist der Schlüssel , der verwendet wird, um das Fenster zu identifizieren, wenn die Position und die Einstellungen automatisch gespeichert werden.
  • Titelleiste : Zeigt das Fenster eine Titelleiste an.
  • Einheitlicher Titel und Symbolleiste : Wenn das Fenster eine Symbolleiste enthält, sollte sie Teil der Titelleiste sein.
  • Inhaltsansicht in voller Größe : Ermöglicht, dass sich der Inhaltsbereich des Fensters unter der Titelleiste befindet.
  • Schatten : Hat das Fenster einen Schatten?
  • Texturiert : Texturfenster können Effekte (z. B. Vibranz) verwenden und durch Ziehen an eine beliebige Stelle des Körpers 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 Symbolleistenschaltfläche zum Ausblenden/Anzeigen?
  • Wiederherstellbar : Die Position und einstellungen des Fensters werden automatisch gespeichert und wiederhergestellt.
  • Beim Start sichtbar : Das Fenster wird automatisch angezeigt, wenn die .xib Datei geladen wird.
  • Ausblenden bei Deaktivierung : Das Fenster wird ausgeblendet, wenn die Anwendung in den Hintergrund wechselt.
  • Release When Closed ( Release When Closed ) – Gibt an, dass das Fenster aus dem Arbeitsspeicher gelöscht wird, wenn es geschlossen wird.
  • QuickInfos immer anzeigen : Werden die QuickInfos ständig angezeigt.
  • Ansichtsschleife neu berechnet : Wird die Ansichtsreihenfolge neu berechnet, bevor das Fenster gezeichnet wird.
  • Spaces, Exposé und Cycling : Alle definieren, wie sich das Fenster in diesen macOS-Umgebungen verhält.
  • Vollbildmodus : Bestimmt, ob dieses Fenster in den Vollbildmodus wechseln kann.
  • Animation : Steuert den Typ der Animation, die für das Fenster verfügbar ist.
  • Darstellung : Steuert die Darstellung des Fensters. Derzeit gibt es nur eine Erscheinung, Aqua.

Weitere Informationen finden Sie in der Dokumentation "Einführung in Windows und NSWindow " von Apple.

Festlegen der Standardgröße und des Speicherorts

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

Standardgröße und -speicherort

Von hier aus können Sie die anfangse Größe des Fensters festlegen, ihm eine minimale und maximale Größe geben, die ursprüngliche Position auf dem Bildschirm festlegen und die Rahmen um das Fenster herum steuern.

Festlegen eines benutzerdefinierten Standard Fenstercontrollers

Um Outlets und Aktionen erstellen zu können, um Benutzeroberflächenelemente 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 Xcode-Schnittstellen-Generator.

  2. Wählen Sie die NSWindowController in der Entwurfsoberfläche 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 zu Visual Studio für Mac zurück, um sie zu synchronisieren.

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

    Auswählen des Windows-Controllers

  6. Öffnen Sie das Storyboard im Xcode-Schnittstellen-Generator 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 von Interface Builder zum Erstellen und Aktivieren von Steuerelementen finden Sie in der Dokumentation Einführung in Xcode und Interface Builder .

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

Auswählen einer Symbolleiste aus der Bibliothek

Ziehen Sie als Nächstes eine Textansicht ein, und vergrößern Sie sie, um den Bereich unter der Symbolleiste auszufüllen:

Hinzufügen einer Textansicht

Da die Textansicht verkleinern und wachsen soll, wenn sich die Größe des Fensters ändert, wechseln wir zum Einschränkungs-Editor und fügen 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, wird die Textansicht aufgefordert, sich an die angegebenen X,Y-Koordinaten zu halten und horizontal und vertikal zu vergrößern oder zu verkleinern, wenn die Größe des Fensters geändert wird.

Machen Sie schließlich die Textansicht für Code mit einem Outlet 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 sie mit Xcode zu synchronisieren.

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

Workflow im Standardfenster

Für jedes Fenster, das Sie in Ihrer Xamarin.Mac-Anwendung erstellen und mit dem Sie arbeiten, ist der Prozess im Grunde derselbe wie zuvor:

  1. Für neue Fenster, die ihrem Projekt nicht automatisch hinzugefügt werden, fügen Sie dem Projekt eine neue Fensterdefinition hinzu. Dies wird unten ausführlich erläutert.
  2. Doppelklicken Sie auf die Main.storyboard Datei, um den Fensterentwurf zur Bearbeitung im Xcode-Schnittstellen-Generator 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 Zum Arbeiten mit Storyboards ).
  4. Legen Sie alle erforderlichen Fenstereigenschaften im Attributinspektor und im Größeninspektor fest.
  5. Ziehen Sie die Steuerelemente ein, die zum Erstellen Ihrer Schnittstelle 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 sie mit Xcode zu synchronisieren.

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

Anzeigen des Standardfensters

Standardmäßig zeigt eine neue Xamarin.Mac-Anwendung automatisch das in der MainWindow.xib Datei definierte Fenster an, wenn sie gestartet wird:

Ein Beispielfenster, das ausgeführt wird

Da wir den Entwurf dieses Fensters oben geändert haben, enthält es jetzt ein Standardsteuerelement für Symbolleiste und Textansicht . Der folgende Abschnitt in der Datei ist für die Info.plist Anzeige dieses Fensters verantwortlich:

Bearbeiten von Info.plist

Die Dropdownliste Hauptschnittstelle wird verwendet, um das Storyboard auszuwählen, das als Standard App-Benutzeroberfläche (in diesem FallMain.storyboard) verwendet wird.

Dem Projekt wird automatisch ein Ansichtscontroller hinzugefügt, um das angezeigte Hauptfenster (zusammen mit seiner 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 den Titel hat untitled , wann es zum ersten Mal geöffnet wird, also überschreiben wir die ViewWillAppear Methode in der ViewController.cs , um wie folgt aussehen zu können:

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 -Methode festgelegt, da die Ansicht zwar in den ViewDidLoad Arbeitsspeicher geladen wird, aber noch nicht vollständig instanziiert ist. Beim Zugriff auf die Title -Eigenschaft in der ViewDidLoad -Methode erhalten wir eine null Ausnahme, da das Fenster noch nicht erstellt und mit der -Eigenschaft verbunden wurde.

Programmgesteuertes Schließen eines Fensters

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

PerformClose

Das Aufrufen der PerformClose -Methode eines NSWindow simuliert, dass der Benutzer auf die Schaltfläche Schließen des Fensters klickt, indem er die Schaltfläche vorübergehend hervorhebt und dann das Fenster schließt.

Wenn die Anwendung das NSWindow- WillClose Ereignis implementiert, wird es ausgelöst, bevor das Fenster geschlossen wird. Wenn das Ereignis zurückgibt false, wird das Fenster nicht geschlossen. Wenn das Fenster keine Schließen-Schaltfläche aufweist oder aus irgendeinem Grund nicht geschlossen werden kann, gibt das Betriebssystem den Warnungston aus.

Beispiel:

MyWindow.PerformClose(this);

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

Schließen

Das Aufrufen der Close -Methode von NSWindow simuliert nicht, dass der Benutzer auf die Schaltfläche Schließen des Fensters klickt, indem er die Schaltfläche vorübergehend hervorhebt. Es wird einfach das Fenster geschlossen.

Ein Fenster muss nicht sichtbar sein, um geschlossen zu werden, und eine NSWindowWillCloseNotification Benachrichtigung wird an das Standardbenachrichtigungscenter für das fenster gesendet, das geschlossen wird.

Die Close Methode unterscheidet sich in zwei wichtigen Wegen von der PerformClose -Methode:

  1. Es wird nicht versucht, das Ereignis auszulösen WillClose .
  2. Es wird nicht simuliert, dass der Benutzer auf die Schaltfläche Schließen klickt, indem er die Schaltfläche vorübergehend hervor hebt.

Beispiel:

MyWindow.Close();

Würde die MyWindowNSWindow instance schließen.

Geänderte Fensterinhalte

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änderte Inhalte enthält, wird im Widget Schließen ein kleiner schwarzer Punkt angezeigt:

Ein Fenster mit dem geänderten Marker

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 anzeigen und dem Benutzer erlauben, seine Änderungen zuerst zu speichern:

Ein Speicherblatt, das beim Schließen des Fensters angezeigt wird

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;

Sobald die Änderung gespeichert wurde, löschen Sie das geänderte Flag mithilfe von:

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

Speichern von Änderungen vor dem Schließen eines Fensters

Um watch, dass der Benutzer ein Fenster schließt und ihm das Speichern geänderter Inhalte im Voraus ermöglicht, müssen Sie eine Unterklasse von NSWindowDelegate erstellen und die WindowShouldClose -Methode überschreiben. 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 instance dieses Delegats 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 windows geänderte Inhalte enthält, und dem Benutzer erlauben, die Änderungen vor dem Beenden zu speichern. Bearbeiten Sie hierzu Ihre AppDelegate.cs Datei, überschreiben Sie die ApplicationShouldTerminate -Methode und lassen Sie sie wie folgt aussehen:

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. Beispielsweise kann ein Text-Editor mehrere Textdateien gleichzeitig zur Bearbeitung geöffnet haben. Standardmäßig verfügt eine neue Xamarin.Mac-Anwendung über ein Dateimenü mit einem neuen Element, das automatisch mit der newDocument:Aktion verbunden ist.

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 nicht gespeicherter Dateien nachzuverfolgen, damit wir dem Benutzer Feedback geben können (gemäß den oben beschriebenen Apple-Richtlinien).

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 des Fenstercontrollers, lädt das neue Fenster, macht es zum Haupt- und Schlüsselfenster und legt den 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 unsere geöffneten Fenster automatisch nachverfolgt und verarbeitet:

Das Fenstermenü

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

Abrufen des aktuell aktiven Fensters

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

var window = NSApplication.SharedApplication.KeyWindow;

Sie kann in jeder Klasse oder Methode aufgerufen werden, die auf das aktuelle Schlüsselfenster zugreifen muss. Wenn derzeit kein Fenster geöffnet ist, wird 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. Beispielsweise, um festzustellen, ob eine Datei, die der Benutzer öffnen möchte, bereits in einem beendenden Fenster geöffnet ist.

Die NSApplication.SharedApplication verwaltet 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. 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 ViewController Klasse in unserer App umgewandelt und der Wert einer benutzerdefinierten Path Eigenschaft anhand des Pfads einer Datei getestet, die der Benutzer öffnen möchte. Wenn die Datei bereits geöffnet ist, wird dieses Fenster an die Front gebracht.

Anpassen der Fenstergröße im Code

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

Im Gegensatz zu iOS, wo die obere linke Ecke (0,0) darstellt, verwendet macOS ein mathematisches Koordinatensystem, bei dem die linke untere Ecke des Bildschirms (0,0) darstellt. In iOS erhöhen sich die Koordinaten, wenn Sie sich nach unten nach rechts bewegen. In macOS erhöhen sich die Koordinaten im Wert nach oben nach rechts.

Der folgende Beispielcode ändert die Größe eines Fensters:

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 Mindest- und Höchstgrößen einhalten, die Sie im Schnittstellen-Generator festgelegt haben. Dies wird nicht automatisch berücksichtigt, und Sie können das Fenster größer oder kleiner als diese Grenzwerte machen.

Ü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. Beispielsweise, um Inhalte so zu erstellen, dass sie der neuen Größe entsprechen.

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

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. 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 erst benachrichtigt zu werden, nachdem der Benutzer die Größe des Fensters geändert 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 eines Fensters und der dargestellten Datei

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

Bearbeiten wir unsere ViewController.cs Datei und nehmen die folgenden Änderungen vor:

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 Zustand der DocumentEdited Eigenschaft. Wenn dies der Grund ist true , müssen wir dem Benutzer die Möglichkeit geben, die Änderungen an 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 Warnung:

Anzeigen eines Speicherdialogfelds

Wenn Sie ein Dokument aus einer Datei laden, legen Sie den Titel des Fensters mithilfe der -Methode auf den Namen der window.SetTitleWithRepresentedFilename (Path.GetFileName(path)); Datei fest (wobei es sich um eine Zeichenfolge handelt, 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 vom Betriebssystem bekannten Dateityp verweist, 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 Dokumentfensters muss eine Xamarin.Mac-Anwendung dem Benutzer möglicherweise 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 zur Bearbeitung im Xcode-Schnittstellen-Generator 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 für die Storyboard-ID folgendes einPreferencesWindow:

    Festlegen der Storyboard-ID

  4. Entwerfen Sie Ihre Schnittstelle:

    Entwerfen der Benutzeroberfläche

  5. Öffnen Sie das App-Menü (MacWindows), wählen Sie Einstellungen... aus, Control-Click und ziehen Sie in das neue Fenster:

    Erstellen einer Segue

  6. Wählen Sie im Popupmenü Die Option Anzeigen aus.

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

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

Menü

Verwenden von Bereichen

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

Genau wie bei jedem anderen Typ von Fenstern, die Sie in Ihrer Xamarin.Mac-Anwendung erstellen und mit denen Sie arbeiten, ist der Prozess im Grunde der gleiche:

  1. Fügen Sie dem Projekt eine neue Fensterdefinition hinzu.
  2. Doppelklicken Sie auf die .xib Datei, um den Fensterentwurf zur Bearbeitung im Xcode-Schnittstellen-Generator zu öffnen.
  3. Legen Sie alle erforderlichen Fenstereigenschaften im Attributinspektor und im Größeninspektor fest.
  4. Ziehen Sie die Steuerelemente ein, die zum Erstellen Ihrer Schnittstelle 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 sie mit Xcode zu synchronisieren.

Im Attributinspektor stehen Ihnen die folgenden Optionen speziell für Panels zur Auswahl:

Attributinspektor

  • Stil : Ermöglicht ihnen das Anpassen des Stils des Bereichs über: Regulärer Bereich (sieht wie ein Standardfenster aus), Hilfsprogrammbereich (hat eine kleinere Titelleiste), HUD-Bereich (ist durchscheinend und die Titelleiste ist Teil des Hintergrunds).
  • Nicht aktivierend : Bestimmt im Bereich wird zum Schlüsselfenster.
  • Document Modal : Wenn Document Modal, wird der Bereich nur über den Fenstern der Anwendung schweben, andernfalls wird er über 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 SieNeue Dateihinzufügen>... aus.

  2. Wählen Sie im Dialogfeld Neue Datei die Option Xamarin.Mac>Cocoa Window with 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 zur Bearbeitung in Interface Builder 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. Binden Sie den Bereich mit dem Fenster "Besitzer - - " der Dateiein:

    Ziehen, um das Panel nach oben zu verkabeln

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

    Festlegen der Klasse des Bereichs

  8. Speichern Sie Ihre Änderungen, und kehren Sie zu Visual Studio für Mac zurück, um sie 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 lassen Sie die DidFinishLaunching Methode wie folgt aussehen:

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

Wenn wir unsere Anwendung ausführen, wird der Bereich angezeigt:

Der Bereich in einer ausgeführten App

Wichtig

Panelfenster sind von Apple veraltet und sollten durch Inspector Interfaces ersetzt werden. Ein vollständiges Beispiel zum Erstellen eines Inspektors in einer Xamarin.Mac-App finden Sie in unserer MacInspector-Beispiel-App .

Zusammenfassung

In diesem Artikel wird die Arbeit mit Windows und Panels in einer Xamarin.Mac-Anwendung ausführlich erläutert. Wir haben die verschiedenen Typen und Verwendungen von Windows und Panels, das Erstellen und Verwalten von Windows und Panels im Xcode-Schnittstellen-Generator und das Arbeiten mit Windows und Panels in C#-Code gesehen.