Windows dans Xamarin.Mac

Cet article traite de l’utilisation des fenêtres et des panneaux dans une application Xamarin.Mac. Il décrit la création de fenêtres et de panneaux dans Xcode et Interface Builder, leur chargement à partir de storyboards et de fichiers .xib, et leur utilisation par programmation.

Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes Windows et panneaux qu’un développeur travaillant dans Objective-C et Xcode . Étant donné que Xamarin.Mac s’intègre directement à Xcode, vous pouvez utiliser le Générateur d’interface de Xcode pour créer et gérer vos Fenêtres et panneaux (ou éventuellement les créer directement en code C#).

En fonction de son objectif, une application Xamarin.Mac peut présenter un ou plusieurs Windows à l’écran pour gérer et coordonner les informations qu’elle affiche et utilise. Les fonctions principales d’une fenêtre sont les suivantes :

  1. Pour fournir une zone dans laquelle les vues et les contrôles peuvent être placés et gérés.
  2. Pour accepter et répondre aux événements en réponse à l’interaction de l’utilisateur avec le clavier et la souris.

Windows peut être utilisé dans un état sans mode (par exemple, un éditeur de texte qui peut avoir plusieurs documents ouverts à la fois) ou modal (par exemple, une boîte de dialogue Exporter qui doit être ignorée pour que l’application puisse continuer).

Les panneaux sont un type spécial de fenêtre (une sous-classe de la classe de base NSWindow ), qui sert généralement une fonction auxiliaire dans une application, telle que les fenêtres utilitaires telles que les inspecteurs de format texte et le sélecteur de couleurs système.

Modification d’une fenêtre dans Xcode

Dans cet article, nous allons aborder les principes fondamentaux de l’utilisation de Windows et de Panneaux dans une application Xamarin.Mac. Il est fortement recommandé de commencer par travailler sur l’article Hello, Mac , en particulier les sections Introduction to Xcode et Interface Builderet Outlets and Actions , car il couvre les concepts et techniques clés que nous allons utiliser dans cet article.

Vous pouvez également consulter la section Exposition des classes/méthodes C# du Objective-C document Xamarin.Mac Internals . Elle explique les commandes Register et Export utilisées pour relier vos classes C# à Objective-C des objets et des éléments d’interface utilisateur.

Présentation des fenêtres

Comme indiqué ci-dessus, une fenêtre fournit une zone dans laquelle les affichages et les contrôles peuvent être placés et gérés et répond aux événements en fonction de l’interaction de l’utilisateur (par le biais du clavier ou de la souris).

Selon Apple, il existe cinq types main de Windows dans une application macOS :

  • Fenêtre de document : une fenêtre de document contient des données utilisateur basées sur des fichiers, telles qu’une feuille de calcul ou un document texte.
  • Fenêtre d’application : une fenêtre d’application est la fenêtre main d’une application qui n’est pas basée sur un document (comme l’application Calendrier sur un Mac).
  • Panneau : un panneau flotte au-dessus des autres fenêtres et fournit des outils ou des contrôles que les utilisateurs peuvent utiliser lorsque les documents sont ouverts. Dans certains cas, un panneau peut être translucide (par exemple quand vous travaillez avec des graphiques volumineux).
  • Boîte de dialogue : une boîte de dialogue apparaît en réponse à une action de l’utilisateur et fournit généralement des moyens pour les utilisateurs d’effectuer l’action. Une boîte de dialogue nécessite une réponse de l’utilisateur avant de pouvoir être fermée. (Voir Utilisation des boîtes de dialogue)
  • Alertes : une alerte est un type spécial de boîte de dialogue qui s’affiche lorsqu’un problème grave se produit (par exemple, une erreur) ou en tant qu’avertissement (par exemple, la préparation de la suppression d’un fichier). Étant donné qu’une alerte est une boîte de dialogue, elle nécessite également une réponse de l’utilisateur avant de pouvoir être fermée. (Voir Utilisation des alertes)

Pour plus d’informations, consultez la section À propos de Windows des thèmes de conception macOS d’Apple.

Fenêtres principales, à clé et inactives

Windows dans une application Xamarin.Mac peut se présenter et se comporter différemment en fonction de la façon dont l’utilisateur interagit actuellement avec eux. La fenêtre de document ou d’application la plus en tête qui est actuellement au centre de l’attention de l’utilisateur est appelée fenêtre principale. Dans la plupart des cas, cette fenêtre est également la fenêtre clé (la fenêtre qui accepte actuellement l’entrée utilisateur). Mais ce n’est pas toujours le cas, par exemple, un sélecteur de couleurs peut être ouvert et être la fenêtre Clé avec laquelle l’utilisateur interagit pour modifier l’état d’un élément dans la fenêtre de document (qui serait toujours la fenêtre principale).

Les fenêtres Main et Key (si elles sont séparées) sont toujours actives. Les fenêtres inactives sont des fenêtres ouvertes qui ne sont pas au premier plan. Par exemple, une application d’éditeur de texte peut avoir plusieurs documents ouverts à la fois, seule la fenêtre principale est active, toutes les autres sont inactives.

Pour plus d’informations, consultez la section À propos de Windows des thèmes de conception macOS d’Apple.

Nommage des fenêtres

Une fenêtre peut afficher une barre de titre et, lorsque le titre est affiché, il s’agit généralement du nom de l’application, du nom du document sur lequel l’on travaille ou de la fonction de la fenêtre (par exemple, Inspector). Certaines applications n’affichent pas de barre de titre, car elles sont reconnaissables par vue et ne fonctionnent pas avec des documents.

Apple suggère les recommandations suivantes :

  • Utilisez le nom de votre application pour le titre d’une fenêtre main non-document.
  • Nommez une nouvelle fenêtre untitledde document . Pour le premier nouveau document, n’ajoutez pas de nombre au titre (par untitled 1exemple). Si l’utilisateur crée un autre document avant d’enregistrer et de titiller le premier, appelez cette fenêtre untitled 2, untitled 3, etc.

Pour plus d’informations, consultez la section Nommage Windows des thèmes de conception macOS d’Apple.

Fenêtres plein écran

Dans macOS, la fenêtre d’une application peut passer en plein écran en masquant tout, y compris la barre de menus de l’application (qui peut être révélée en déplaçant le curseur vers le haut de l’écran) pour fournir une interaction sans distraction avec son contenu.

Apple suggère les recommandations suivantes :

  • Déterminez s’il est judicieux qu’une fenêtre passe en mode plein écran. Les applications qui fournissent de brèves interactions (comme une calculatrice) ne doivent pas fournir un mode plein écran.
  • Affichez la barre d’outils si la tâche en plein écran l’exige. En général, la barre d’outils est masquée en mode plein écran.
  • La fenêtre plein écran doit avoir toutes les fonctionnalités dont les utilisateurs ont besoin pour effectuer la tâche.
  • Si possible, évitez d’interagir avec le Finder lorsque l’utilisateur est dans une fenêtre plein écran.
  • Tirez parti de l’espace d’écran accru sans déplacer le focus de la tâche main.

Pour plus d’informations, consultez la section Windows plein écran des thèmes de conception macOS d’Apple.

Panneaux

Un panneau est une fenêtre auxiliaire qui contient des contrôles et des options qui affectent le document ou la sélection actif (par exemple, le sélecteur de couleurs système) :

Panneau de couleurs

Les panneaux peuvent être spécifiques à l’application ou à l’échelle du système. App-Specific Panneaux flottent au-dessus des fenêtres de document de l’application et disparaissent lorsque l’application est en arrière-plan. Les panneaux à l’échelle du système (tels que le panneau Polices ) flottent sur toutes les fenêtres ouvertes, quelle que soit l’application.

Apple suggère les recommandations suivantes :

  • En général, utilisez un panneau standard, les panneaux transparents ne doivent être utilisés qu’avec parcimonie et pour les tâches gourmandes en graphiques.
  • Envisagez d’utiliser un panneau pour permettre aux utilisateurs d’accéder facilement à des contrôles importants ou à des informations qui affectent directement leur tâche.
  • Masquez et affichez les panneaux en fonction des besoins.
  • Les panneaux doivent toujours inclure la barre de titre.
  • Les panneaux ne doivent pas inclure de bouton de réduction actif.

Inspecteurs

La plupart des applications macOS modernes présentent des contrôles et des options auxiliaires qui affectent le document ou la sélection actif en tant qu’inspecteurs qui font partie de la fenêtre principale (comme l’application Pages ci-dessous), au lieu d’utiliser des fenêtres de panneau :

Exemple d’inspecteur

Pour plus d’informations, consultez la section Panneaux des thèmes de conception macOS d’Apple et notre exemple d’application MacInspector pour une implémentation complète d’une interface Inspector dans une application Xamarin.Mac.

Création et maintenance de fenêtres dans Xcode

Lorsque vous créez une application Xamarin.Mac Cocoa, vous obtenez une fenêtre vide standard par défaut. Cette fenêtre est définie dans un .storyboard fichier automatiquement inclus dans le projet. Pour modifier la conception de vos fenêtres, dans le Explorateur de solutions, double-cliquez sur le Main.storyboard fichier :

Sélection du storyboard main

La conception de fenêtre s’ouvre dans le générateur d’interface de Xcode :

Modification de l’interface utilisateur dans Xcode

Dans l’inspecteur d’attributs, vous pouvez utiliser plusieurs propriétés pour définir et contrôler votre fenêtre :

  • Titre : il s’agit du texte qui sera affiché dans la barre de titre de la fenêtre.
  • Enregistrement automatique : il s’agit de la clé qui sera utilisée pour identifier la fenêtre lorsque sa position et ses paramètres sont automatiquement enregistrés.
  • Barre de titre : la fenêtre affiche-t-elle une barre de titre.
  • Titre et barre d’outils unifiés : si la fenêtre inclut une barre d’outils, doit-elle faire partie de la barre de titre.
  • Affichage contenu de taille totale : permet à la zone de contenu de la fenêtre d’être sous la barre de titre.
  • Ombre : la fenêtre a-t-elle une ombre.
  • Texturé : les fenêtres texturées peuvent utiliser des effets (comme la vivacité) et peuvent être déplacées en faisant glisser n’importe où sur leur corps.
  • Fermer : la fenêtre a-t-elle un bouton Fermer.
  • Réduire : la fenêtre a-t-elle un bouton réduire.
  • Redimensionner : la fenêtre a-t-elle un contrôle de redimensionnement.
  • Bouton barre d’outils : la fenêtre a-t-elle un bouton masquer/afficher la barre d’outils.
  • Restaurable : la position et les paramètres de la fenêtre sont-ils automatiquement enregistrés et restaurés.
  • Visible au lancement : la fenêtre s’affiche-t-elle automatiquement lorsque le .xib fichier est chargé.
  • Masquer lors de la désactivation : la fenêtre est-elle masquée lorsque l’application entre en arrière-plan.
  • Libérer quand elle est fermée : la fenêtre est-elle vidée de la mémoire lorsqu’elle est fermée.
  • Toujours afficher les info-bulles : les info-bulles sont-elles affichées en permanence.
  • Recalcule la boucle d’affichage : l’ordre d’affichage est-il recalculé avant le dessin de la fenêtre.
  • Espaces, Exposé et Cycle : tous définissent le comportement de la fenêtre dans ces environnements macOS.
  • Plein écran : détermine si cette fenêtre peut passer en mode plein écran.
  • Animation : contrôle le type d’animation disponible pour la fenêtre.
  • Apparence : contrôle l’apparence de la fenêtre. Pour l’instant, il n’y a qu’une seule apparence, Aqua.

Pour plus d’informations, consultez la documentation Présentation d’Apple sur Windows et NSWindow .

Définition de la taille et de l’emplacement par défaut

Pour définir la position initiale de votre fenêtre et contrôler sa taille, basculez vers l’inspecteur de taille :

Taille et emplacement par défaut

À partir de là, vous pouvez définir la taille initiale de la fenêtre, lui donner une taille minimale et maximale, définir l’emplacement initial sur l’écran et contrôler les bordures autour de la fenêtre.

Définition d’un contrôleur de fenêtre de main personnalisé

Pour pouvoir créer des sorties et des actions afin d’exposer des éléments d’interface utilisateur au code C#, l’application Xamarin.Mac doit utiliser un contrôleur de fenêtre personnalisé.

Effectuez les actions suivantes :

  1. Ouvrez le Storyboard de l’application dans le Générateur d’interface de Xcode.

  2. Sélectionnez le NSWindowController dans l’Aire de conception.

  3. Basculez vers la vue Inspecteur d’identité et entrez WindowController comme Nom de la classe :

    Définition du nom de la classe

  4. Enregistrez vos modifications et revenez à Visual Studio pour Mac à synchroniser.

  5. Un WindowController.cs fichier sera ajouté à votre projet dans le Explorateur de solutions de Visual Studio pour Mac :

    Sélection du contrôleur Windows

  6. Rouvrez le storyboard dans le générateur d’interface de Xcode.

  7. Le WindowController.h fichier sera disponible pour une utilisation :

    Modification du fichier WindowController.h

Ajout d’éléments d’interface utilisateur

Pour définir le contenu d’une fenêtre, faites glisser les contrôles de l’inspecteur de bibliothèque vers l’éditeur d’interface. Consultez notre documentation Introduction à Xcode et Interface Builder pour plus d’informations sur l’utilisation d’Interface Builder pour créer et activer des contrôles.

Par exemple, faisons glisser une barre d’outils de l’inspecteur de bibliothèque vers la fenêtre de l’éditeur d’interface :

Sélection d’une barre d’outils dans la bibliothèque

Ensuite, faites glisser un affichage texte et le dimensionner pour remplir la zone sous la barre d’outils :

Ajout d’un affichage texte

Étant donné que nous voulons que l’affichage texte diminue et augmente à mesure que la taille de la fenêtre change, nous allons basculer vers l’éditeur de contraintes et ajouter les contraintes suivantes :

Contraintes d’édition

En cliquant sur les quatre faisceaux I rouges en haut de l’éditeur et en cliquant sur Ajouter 4 contraintes, nous disons à l’affichage de texte de s’en tenir aux coordonnées X,Y spécifiées et de croître ou de réduire horizontalement et verticalement à mesure que la fenêtre est redimensionnée.

Enfin, exposez l’affichage texte au code à l’aide d’un outlet (en veillant à sélectionner le ViewController.h fichier) :

Configuration d’une prise

Enregistrez vos modifications et revenez à Visual Studio pour Mac pour synchroniser avec Xcode.

Pour plus d’informations sur l’utilisation des points de vente et des actions, consultez notre documentation outlet et action .

Flux de travail de fenêtre standard

Pour toutes les fenêtres que vous créez et utilisez dans votre application Xamarin.Mac, le processus est essentiellement le même que celui que nous venons de faire ci-dessus :

  1. Pour les nouvelles fenêtres qui ne sont pas ajoutées automatiquement par défaut à votre projet, ajoutez une nouvelle définition de fenêtre au projet. Cela sera abordé en détail ci-dessous.
  2. Double-cliquez sur le Main.storyboard fichier pour ouvrir la conception de fenêtre à modifier dans le Générateur d’interface de Xcode.
  3. Faites glisser une nouvelle fenêtre dans la conception de l’interface utilisateur et raccordez la fenêtre à la fenêtre principale à l’aide de Segues (pour plus d’informations, consultez la section Segues de notre documentation Utilisation des storyboards ).
  4. Définissez toutes les propriétés de fenêtre requises dans l’inspecteur d’attribut et l’inspecteur de taille.
  5. Faites glisser les contrôles requis pour générer votre interface et configurez-les dans l’inspecteur d’attributs.
  6. Utilisez l’inspecteur de taille pour gérer le redimensionnement de vos éléments d’interface utilisateur.
  7. Exposez les éléments d’interface utilisateur de la fenêtre au code C# via des sorties et des actions.
  8. Enregistrez vos modifications et revenez à Visual Studio pour Mac pour synchroniser avec Xcode.

Maintenant que nous avons créé une fenêtre de base, nous allons examiner les processus typiques d’une application Xamarin.Mac quand vous utilisez windows.

Affichage de la fenêtre par défaut

Par défaut, une nouvelle application Xamarin.Mac affiche automatiquement la fenêtre définie dans le MainWindow.xib fichier au démarrage :

Exemple de fenêtre en cours d’exécution

Étant donné que nous avons modifié la conception de cette fenêtre ci-dessus, elle inclut désormais un contrôle Barre d’outils et Affichage de texte par défaut. La section suivante du Info.plist fichier est chargée d’afficher cette fenêtre :

Modification d’Info.plist

La liste déroulante Interface principale permet de sélectionner le storyboard qui sera utilisé comme interface utilisateur de l’application main (dans ce casMain.storyboard).

Un contrôleur d’affichage est automatiquement ajouté au projet pour contrôler la fenêtre principale affichée (ainsi que son affichage principal). Il est défini dans le ViewController.cs fichier et joint au propriétaire du fichier dans le générateur d’interface sous l’inspecteur d’identité :

Définition du propriétaire du fichier

Pour notre fenêtre, nous aimerions qu’elle ait un titre de untitled lorsqu’elle s’ouvre pour la première fois. Nous allons donc remplacer la ViewWillAppear méthode dans le ViewController.cs pour ressembler à ce qui suit :

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

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

Notes

La propriété de la Title fenêtre est définie dans la ViewWillAppear méthode plutôt que dans la ViewDidLoad méthode , car, bien que la vue soit chargée en mémoire, elle n’est pas encore entièrement instanciée. En accédant à la Title propriété dans la ViewDidLoad méthode , nous obtiendrons une null exception, car la fenêtre n’a pas encore été construite et connectée à la propriété.

Fermeture d’une fenêtre par programmation

Il peut arriver que vous souhaitiez fermer une fenêtre par programmation dans une application Xamarin.Mac, en dehors du fait que l’utilisateur clique sur le bouton Fermer de la fenêtre ou utilise un élément de menu. macOS offre deux façons différentes de fermer un NSWindow par programmation : PerformClose et Close.

PerformClose

L’appel de la PerformClose méthode d’un NSWindow simule l’utilisateur qui clique sur le bouton Fermer de la fenêtre en mettant momentanément en surbrillance le bouton, puis en fermant la fenêtre.

Si l’application implémente l’événement NSWindowde WillClose , celui-ci est déclenché avant la fermeture de la fenêtre. Si l’événement retourne false, la fenêtre ne sera pas fermée. Si la fenêtre n’a pas de bouton Fermer ou ne peut pas être fermée pour une raison quelconque, le système d’exploitation émet le son d’alerte.

Par exemple :

MyWindow.PerformClose(this);

Tenterait de fermer le MyWindowNSWindow instance. S’il réussit, la fenêtre est fermée, sinon le son d’alerte est émis et le reste ouvert.

Fermer

L’appel de la Close méthode d’un NSWindow ne simule pas que l’utilisateur clique sur le bouton Fermer de la fenêtre en mettant momentanément le bouton en surbrillance, il ferme simplement la fenêtre.

Une fenêtre n’a pas besoin d’être visible pour être fermée et une NSWindowWillCloseNotification notification est publiée dans le Centre de notifications par défaut pour la fenêtre en cours de fermeture.

La Close méthode diffère de deux manières importantes de la PerformClose méthode :

  1. Il ne tente pas de déclencher l’événement WillClose .
  2. Il ne simule pas que l’utilisateur clique sur le bouton Fermer en mettant momentanément le bouton en surbrillance.

Par exemple :

MyWindow.Close();

J’aimerais fermer le MyWindowNSWindow instance.

Contenu windows modifié

Dans macOS, Apple a fourni un moyen d’informer l’utilisateur que le contenu d’une fenêtre (NSWindow) a été modifié par l’utilisateur et doit être enregistré. Si la fenêtre contient du contenu modifié, un petit point noir s’affiche dans son widget Fermer :

Fenêtre avec le marqueur modifié

Si l’utilisateur tente de fermer la fenêtre ou de quitter l’application Mac alors qu’il y a des modifications non enregistrées dans le contenu de la fenêtre, vous devez présenter une boîte de dialogue ou une feuille modale et autoriser l’utilisateur à enregistrer d’abord ses modifications :

Une feuille d’enregistrement s’affiche lorsque la fenêtre est fermée

Marquage d’une fenêtre comme modifiée

Pour marquer une fenêtre comme ayant modifié le contenu, utilisez le code suivant :

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

Et une fois la modification enregistrée, effacez l’indicateur modifié à l’aide de :

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

Enregistrement des modifications avant de fermer une fenêtre

Pour watch à l’utilisateur fermant une fenêtre et lui permettant d’enregistrer le contenu modifié au préalable, vous devez créer une sous-classe de NSWindowDelegate et remplacer sa WindowShouldClose méthode. Par exemple :

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

Utilisez le code suivant pour attacher un instance de ce délégué à la fenêtre :

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

Enregistrement des modifications avant de fermer l’application

Enfin, votre application Xamarin.Mac doit case activée pour voir si l’une de ses fenêtres contient du contenu modifié et permettre à l’utilisateur d’enregistrer les modifications avant de quitter. Pour ce faire, modifiez votre AppDelegate.cs fichier, remplacez la ApplicationShouldTerminate méthode et faites-le ressembler à ce qui suit :

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

Utilisation de plusieurs fenêtres

La plupart des applications Mac basées sur des documents peuvent modifier plusieurs documents en même temps. Par exemple, un éditeur de texte peut avoir plusieurs fichiers texte ouverts pour modification en même temps. Par défaut, une nouvelle application Xamarin.Mac a un menu Fichier avec un nouvel élément automatiquement connecté à l’actionnewDocument:.

Le code ci-dessous active ce nouvel élément et permet à l’utilisateur d’ouvrir plusieurs copies de la fenêtre principale pour modifier plusieurs documents à la fois.

Modifiez le AppDelegate.cs fichier et ajoutez la propriété calculée suivante :

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

Utilisez-le pour suivre le nombre de fichiers non enregistrés afin que nous puissions envoyer des commentaires à l’utilisateur (conformément aux instructions d’Apple, comme indiqué ci-dessus).

Ensuite, ajoutez la méthode suivante :

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

Ce code crée une nouvelle version de notre contrôleur de fenêtre, charge la nouvelle fenêtre, en fait la fenêtre principale et la fenêtre clé et définit son titre. Maintenant, si nous exécutons notre application et que nous sélectionnons Nouveau dans le menu Fichier , une nouvelle fenêtre d’éditeur s’ouvre et s’affiche :

Une nouvelle fenêtre sans titre a été ajoutée

Si nous ouvrons le menu Windows , vous pouvez voir que l’application suit et gère automatiquement nos fenêtres ouvertes :

Menu Windows

Pour plus d’informations sur l’utilisation des menus dans une application Xamarin.Mac, consultez notre documentation Utilisation des menus .

Obtention de la fenêtre active

Dans une application Xamarin.Mac qui peut ouvrir plusieurs fenêtres (documents), vous devez parfois obtenir la fenêtre la plus haute actuelle (la fenêtre clé). Le code suivant retourne la fenêtre de clé :

var window = NSApplication.SharedApplication.KeyWindow;

Il peut être appelé dans n’importe quelle classe ou méthode qui doit accéder à la fenêtre clé actuelle. Si aucune fenêtre n’est actuellement ouverte, elle retourne null.

Accès à toutes les fenêtres d’application

Il peut arriver que vous deviez accéder à toutes les fenêtres actuellement ouvertes par votre application Xamarin.Mac. Par exemple, pour voir si un fichier que l’utilisateur souhaite ouvrir est déjà ouvert dans une fenêtre sortante.

Le NSApplication.SharedApplication conserve une Windows propriété qui contient un tableau de toutes les fenêtres ouvertes dans votre application. Vous pouvez itérer sur ce tableau pour accéder à toutes les fenêtres actuelles de l’application. Par exemple :

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

Dans l’exemple de code, nous créons un cast de chaque fenêtre retournée dans la classe personnalisée ViewController de notre application et testons la valeur d’une propriété personnalisée Path par rapport au chemin d’accès d’un fichier que l’utilisateur souhaite ouvrir. Si le fichier est déjà ouvert, nous mettons cette fenêtre à l’avant.

Ajustement de la taille de la fenêtre dans le code

Parfois, l’application doit redimensionner une fenêtre dans le code. Pour redimensionner et repositionner une fenêtre, vous ajustez sa Frame propriété. Lorsque vous ajustez la taille d’une fenêtre, vous devez généralement également ajuster son origine, afin de conserver la fenêtre au même emplacement en raison du système de coordonnées de macOS.

Contrairement à iOS où le coin supérieur gauche représente (0,0), macOS utilise un système de coordonnées mathématiques où le coin inférieur gauche de l’écran représente (0,0). Dans iOS, les coordonnées augmentent à mesure que vous descendez vers la droite. Dans macOS, les coordonnées augmentent en valeur vers la droite.

L’exemple de code suivant redimensionne une fenêtre :

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

Important

Lorsque vous ajustez une taille de fenêtre et un emplacement dans le code, vous devez vous assurer que vous respectez les tailles minimales et maximales que vous avez définies dans le Générateur d’interface. Cela ne sera pas automatiquement respecté et vous pourrez rendre la fenêtre plus grande ou plus petite que ces limites.

Modification de la taille de la fenêtre de surveillance

Il peut arriver que vous deviez surveiller les modifications apportées à la taille d’une fenêtre à l’intérieur de votre application Xamarin.Mac. Par exemple, pour redessiner du contenu en fonction de la nouvelle taille.

Pour surveiller les modifications de taille, vérifiez d’abord que vous avez affecté une classe personnalisée pour le contrôleur de fenêtre dans le générateur d’interface de Xcode. Par exemple, MasterWindowController dans ce qui suit :

Inspecteur d’identité

Ensuite, modifiez la classe de contrôleur de fenêtre personnalisée et surveillez l’événement DidResize sur la fenêtre du contrôleur pour être averti des changements de taille en direct. Par exemple :

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

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

Si vous le souhaitez, vous pouvez utiliser l’événement DidEndLiveResize pour être averti uniquement une fois que l’utilisateur a fini de modifier la taille de la fenêtre. Par exemple :

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

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

Définition du titre et du fichier représenté d’une fenêtre

Lorsque vous utilisez des fenêtres qui représentent des documents, a une DocumentEdited propriété qui, si elle est définie surtrue, NSWindow affiche un petit point dans le bouton Fermer pour donner à l’utilisateur une indication que le fichier a été modifié et doit être enregistré avant la fermeture.

Nous allons modifier notre ViewController.cs fichier et apporter les modifications suivantes :

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

}

Nous surveillons également l’événement WillClose dans la fenêtre et vérifions l’état de la DocumentEdited propriété. Si c’est true le cas, nous devons donner à l’utilisateur la possibilité d’enregistrer les modifications apportées au fichier. Si nous exécutons notre application et entrez du texte, le point s’affiche :

Fenêtre modifiée

Si vous essayez de fermer la fenêtre, vous recevez une alerte :

Affichage d’une boîte de dialogue d’enregistrement

Si vous chargez un document à partir d’un fichier, définissez le titre de la fenêtre sur le nom du fichier à l’aide de la window.SetTitleWithRepresentedFilename (Path.GetFileName(path)); méthode (étant donné qu’il path s’agit d’une chaîne représentant le fichier en cours d’ouverture). En outre, vous pouvez définir l’URL du fichier à l’aide de la window.RepresentedUrl = url; méthode .

Si l’URL pointe vers un type de fichier connu par le système d’exploitation, son icône s’affiche dans la barre de titre. Si l’utilisateur clique avec le bouton droit sur l’icône, le chemin d’accès au fichier s’affiche.

Modifiez le AppDelegate.cs fichier et ajoutez la méthode suivante :

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

        }
    }
}

Maintenant, si nous exécutons notre application, sélectionnez Ouvrir... dans le menu Fichier , sélectionnez un fichier texte dans la boîte de dialogue Ouvrir et ouvrez-le :

Boîte de dialogue ouverte

Le fichier s’affiche et le titre est défini avec l’icône du fichier :

Contenu d’un fichier chargé

Ajout d’une nouvelle fenêtre à un projet

Outre la fenêtre de document main, une application Xamarin.Mac peut avoir besoin d’afficher d’autres types de fenêtres pour l’utilisateur, telles que préférences ou panneaux d’inspecteur.

Pour ajouter une nouvelle fenêtre, procédez comme suit :

  1. Dans le Explorateur de solutions, double-cliquez sur le fichier pour l’ouvrir Main.storyboard et le modifier dans le générateur d’interface de Xcode.

  2. Faites glisser un nouveau contrôleur de fenêtre à partir de la bibliothèque et déposez-le sur l’aire de conception :

    Sélection d’un nouveau contrôleur de fenêtre dans la bibliothèque

  3. Dans l’inspecteur d’identité, entrez PreferencesWindow pour l’ID de storyboard :

    Définition de l’ID de table de montage séquentiel

  4. Concevez votre interface :

    Conception de l’interface utilisateur

  5. Ouvrez le menu De l’application (MacWindows), sélectionnez Préférences..., Control-Click et faites glisser vers la nouvelle fenêtre :

    Création d’un segue

  6. Sélectionnez Afficher dans le menu contextuel.

  7. Enregistrez vos modifications et revenez à Visual Studio pour Mac à synchroniser avec Xcode.

Si nous exécutons le code et que nous sélectionnons préférences... dans le menu Application, la fenêtre s’affiche :

Un exemple de menu de préférences

Utilisation des panneaux

Comme indiqué au début de cet article, un panneau flotte au-dessus des autres fenêtres et fournit des outils ou des contrôles que les utilisateurs peuvent utiliser lorsque les documents sont ouverts.

Comme tout autre type de fenêtre que vous créez et utilisez dans votre application Xamarin.Mac, le processus est essentiellement le même :

  1. Ajoutez une nouvelle définition de fenêtre au projet.
  2. Double-cliquez sur le .xib fichier pour ouvrir la conception de fenêtre à modifier dans le Générateur d’interface de Xcode.
  3. Définissez toutes les propriétés de fenêtre requises dans l’inspecteur d’attribut et l’inspecteur de taille.
  4. Faites glisser les contrôles requis pour générer votre interface et configurez-les dans l’inspecteur d’attributs.
  5. Utilisez l’inspecteur de taille pour gérer le redimensionnement de vos éléments d’interface utilisateur.
  6. Exposez les éléments d’interface utilisateur de la fenêtre au code C# via des sorties et des actions.
  7. Enregistrez vos modifications et revenez à Visual Studio pour Mac pour synchroniser avec Xcode.

Dans l’inspecteur d’attributs, vous disposez des options suivantes spécifiques aux panneaux :

Inspecteur d’attributs

  • Style : vous permet d’ajuster le style du panneau à partir de : Panneau standard (ressemble à une fenêtre standard), Panneau utilitaire (a une barre de titre plus petite), Panneau HUD (est translucide et la barre de titre fait partie de l’arrière-plan).
  • Non activation : détermine dans le panneau devient la fenêtre de clé.
  • Document Modal : si document modal, le panneau flotte uniquement au-dessus des fenêtres de l’application, sinon il flotte avant tout.

Pour ajouter un nouveau panneau, procédez comme suit :

  1. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter un>nouveau fichier....

  2. Dans la boîte de dialogue Nouveau fichier, sélectionnez Xamarin.Mac>Cocoa Window with Controller :

    Ajout d’un nouveau contrôleur de fenêtre

  3. Entrez DocumentPanel comme Nom, puis cliquez sur le bouton Nouveau.

  4. Double-cliquez sur le fichier pour l’ouvrir DocumentPanel.xib pour le modifier dans Le Générateur d’interface :

    Modification du panneau

  5. Supprimez la fenêtre existante et faites glisser un panneau à partir de l’inspecteur de bibliothèque dans l’éditeur d’interface :

    Suppression de la fenêtre existante

  6. Accrochez le panneau à lasortie de lafenêtre - Propriétaire - du fichier:

    Glisser pour relier le panneau

  7. Basculez vers l’inspecteur d’identité et définissez la classe du panneau sur DocumentPanel:

    Définition de la classe du panneau

  8. Enregistrez vos modifications et revenez à Visual Studio pour Mac à synchroniser avec Xcode.

  9. Modifiez le DocumentPanel.cs fichier et remplacez la définition de classe comme suit :

    public partial class DocumentPanel : NSPanel

  10. Enregistrez les modifications du fichier.

Modifiez le AppDelegate.cs fichier et faites en sorte que la DidFinishLaunching méthode ressemble à ce qui suit :

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

Si nous exécutons notre application, le panneau s’affiche :

Panneau dans une application en cours d’exécution

Important

Les fenêtres de panneau ont été dépréciées par Apple et doivent être remplacées par des interfaces d’inspecteur. Pour obtenir un exemple complet de création d’un inspecteur dans une application Xamarin.Mac, consultez notre exemple d’application MacInspector .

Résumé

Cet article a examiné en détail l’utilisation de Windows et de panneaux dans une application Xamarin.Mac. Nous avons vu les différents types et utilisations de Windows et panneaux, comment créer et gérer Windows et panneaux dans le Générateur d’interface de Xcode et comment utiliser Windows et les panneaux en code C#.