Boîtes de dialogue dans Xamarin.Mac

Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes dialogues et Fenêtres modales 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 modales (ou éventuellement les créer directement dans le code C#).

Une boîte de dialogue s’affiche en réponse à une action utilisateur et fournit généralement des façons dont les utilisateurs peuvent effectuer l’action. Une boîte de dialogue nécessite une réponse de l’utilisateur avant de pouvoir être fermée.

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

Boîte de dialogue Ouverte

Dans cet article, nous allons aborder les principes fondamentaux de l’utilisation des dialogues et des fenêtres modales dans une application Xamarin.Mac. Il est fortement suggéré que vous travaillez tout d’abord dans l’article Hello, Mac , en particulier les sections Introduction to Xcode and Interface Builder et Outlets and Actions , car elle couvre les concepts et techniques clés que nous utiliserons dans cet article.

Vous pouvez également examiner les classes /méthodes C# exposantes dans Objective-Cla section du document interne Xamarin.Mac, ainsi que les Register Export instructions utilisées pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.

Introduction aux dialogues

Une boîte de dialogue s’affiche en réponse à une action utilisateur (par exemple, l’enregistrement d’un fichier) et permet aux utilisateurs d’effectuer cette action. Une boîte de dialogue nécessite une réponse de l’utilisateur avant de pouvoir être fermée.

Selon Apple, il existe trois façons de présenter un dialogue :

  • Document Modal : une boîte de dialogue Document Modal empêche l’utilisateur d’effectuer toute autre opération dans un document donné jusqu’à ce qu’il soit ignoré.
  • Modal de l’application : une boîte de dialogue Modale d’application empêche l’utilisateur d’interagir avec l’application jusqu’à ce qu’elle soit ignorée.
  • Une boîte de dialogue sans mode permet aux utilisateurs de modifier les paramètres de la boîte de dialogue tout en interagissant avec la fenêtre de document.

N’importe quelle norme NSWindow peut être utilisée comme boîte de dialogue personnalisée en l’affichant modalement :

Exemple de fenêtre modale

Feuilles de boîte de dialogue modale de document

Une feuille est une boîte de dialogue modale attachée à une fenêtre de document donnée, empêchant les utilisateurs d’interagir avec la fenêtre jusqu’à ce qu’ils ignorent la boîte de dialogue. Une feuille est attachée à la fenêtre à partir de laquelle elle apparaît et une seule feuille peut être ouverte pour une fenêtre à tout moment.

Exemple de feuille modale

Préférences Windows

Une fenêtre Préférences est une boîte de dialogue sans mode qui contient les paramètres de l’application que l’utilisateur change rarement. Les préférences Windows incluent souvent une barre d’outils qui permet à l’utilisateur de basculer entre différents groupes de paramètres :

Exemple de fenêtre de préférence

Ouvrir la boîte de dialogue

La boîte de dialogue Ouvrir offre aux utilisateurs un moyen cohérent de rechercher et d’ouvrir un élément dans une application :

Boîte de dialogue Ouvrir

macOS fournit des boîtes de dialogue standard d’impression et de mise en page que votre application peut afficher afin que les utilisateurs puissent avoir une expérience d’impression cohérente dans chaque application qu’ils utilisent.

La boîte de dialogue Imprimer peut être affichée sous la forme d’une boîte de dialogue flottante libre :

Boîte de dialogue Imprimer

Vous pouvez également l’afficher sous la forme d’une feuille :

Feuille d’impression

La boîte de dialogue Mise en page peut s’afficher sous la forme d’une boîte de dialogue flottante libre :

Boîte de dialogue Mise en page

Vous pouvez également l’afficher sous la forme d’une feuille :

Feuille de configuration d’une page

Enregistrer les boîtes de dialogue

La boîte de dialogue Enregistrer offre aux utilisateurs un moyen cohérent d’enregistrer un élément dans une application. La boîte de dialogue Enregistrer comporte deux états : Minimal (également appelé Réduit) :

Boîte de dialogue Enregistrer

Et l’état développé :

Boîte de dialogue d’enregistrement développée

La boîte de dialogue Enregistrer minimale peut également être affichée sous forme de feuille :

Une feuille d’enregistrement minimale

Comme pour la boîte de dialogue Enregistrer développée :

Une feuille d’enregistrement développée

Pour plus d’informations, consultez la section Dialogues des instructions relatives à l’interface humaine OS X d’Apple

Ajout d’une fenêtre modale à un projet

Outre la fenêtre de document principale, une application Xamarin.Mac peut avoir besoin d’afficher d’autres types de fenêtres à 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, ouvrez le Main.storyboard fichier pour modification dans le Générateur d’interface de Xcode.

  2. Faites glisser un nouveau contrôleur d’affichage dans l’aire de conception :

    Sélection d’un contrôleur d’affichage dans la bibliothèque

  3. Dans l’inspecteur d’identité, entrez CustomDialogController le nom de la classe :

    Définition du nom de classe sur CustomDialogController.

  4. Revenez à Visual Studio pour Mac, autorisez-le à se synchroniser avec Xcode et à créer le CustomDialogController.h fichier.

  5. Revenez à Xcode et concevez votre interface :

    Conception de l’interface utilisateur dans Xcode

  6. Créez un segue modal à partir de la fenêtre principale de votre application vers le nouveau contrôleur d’affichage en faisant glisser le contrôle à partir de l’élément d’interface utilisateur qui ouvre la boîte de dialogue vers la fenêtre de la boîte de dialogue. Attribuez l’identificateur ModalSegue:

    Un segue modal

  7. Connecter les actions et les points de sortie :

    Configuration d’une action

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

Faites en sorte que le CustomDialogController.cs fichier ressemble à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace MacDialog
{
    public partial class CustomDialogController : NSViewController
    {
        #region Private Variables
        private string _dialogTitle = "Title";
        private string _dialogDescription = "Description";
        private NSViewController _presentor;
        #endregion

        #region Computed Properties
        public string DialogTitle {
            get { return _dialogTitle; }
            set { _dialogTitle = value; }
        }

        public string DialogDescription {
            get { return _dialogDescription; }
            set { _dialogDescription = value; }
        }

        public NSViewController Presentor {
            get { return _presentor; }
            set { _presentor = value; }
        }
        #endregion

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

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

            // Set initial title and description
            Title.StringValue = DialogTitle;
            Description.StringValue = DialogDescription;
        }
        #endregion

        #region Private Methods
        private void CloseDialog() {
            Presentor.DismissViewController (this);
        }
        #endregion

        #region Custom Actions
        partial void AcceptDialog (Foundation.NSObject sender) {
            RaiseDialogAccepted();
            CloseDialog();
        }

        partial void CancelDialog (Foundation.NSObject sender) {
            RaiseDialogCanceled();
            CloseDialog();
        }
        #endregion

        #region Events
        public EventHandler DialogAccepted;

        internal void RaiseDialogAccepted() {
            if (this.DialogAccepted != null)
                this.DialogAccepted (this, EventArgs.Empty);
        }

        public EventHandler DialogCanceled;

        internal void RaiseDialogCanceled() {
            if (this.DialogCanceled != null)
                this.DialogCanceled (this, EventArgs.Empty);
        }
        #endregion
    }
}

Ce code expose quelques propriétés pour définir le titre et la description du dialogue et quelques événements pour réagir au dialogue annulé ou accepté.

Ensuite, modifiez le ViewController.cs fichier, remplacez la PrepareForSegue méthode et faites-la ressembler à ce qui suit :

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on the segue name
    switch (segue.Identifier) {
    case "ModalSegue":
        var dialog = segue.DestinationController as CustomDialogController;
        dialog.DialogTitle = "MacDialog";
        dialog.DialogDescription = "This is a sample dialog.";
        dialog.DialogAccepted += (s, e) => {
            Console.WriteLine ("Dialog accepted");
            DismissViewController (dialog);
        };
        dialog.Presentor = this;
        break;
    }
}

Ce code initialise le segue que nous avons défini dans le Générateur d’interface de Xcode dans notre boîte de dialogue et configure le titre et la description. Il gère également le choix que l’utilisateur effectue dans la boîte de dialogue.

Nous pouvons exécuter notre application et afficher la boîte de dialogue personnalisée :

Exemple de boîte de dialogue

Pour plus d’informations sur l’utilisation de windows dans une application Xamarin.Mac, consultez notre documentation Sur l’utilisation de Windows .

Création d’une feuille personnalisée

Une feuille est une boîte de dialogue modale attachée à une fenêtre de document donnée, empêchant les utilisateurs d’interagir avec la fenêtre jusqu’à ce qu’ils ignorent la boîte de dialogue. Une feuille est attachée à la fenêtre à partir de laquelle elle apparaît et une seule feuille peut être ouverte pour une fenêtre à tout moment.

Pour créer une feuille personnalisée dans Xamarin.Mac, procédons comme suit :

  1. Dans le Explorateur de solutions, ouvrez le Main.storyboard fichier pour modification dans le Générateur d’interface de Xcode.

  2. Faites glisser un nouveau contrôleur d’affichage dans l’aire de conception :

    Sélection d’un contrôleur d’affichage dans la bibliothèque

  3. Concevez votre interface utilisateur :

    Conception de l’interface utilisateur

  4. Créez une feuille segue à partir de votre fenêtre principale vers le nouveau contrôleur d’affichage :

    Sélection du type de segue de feuille

  5. Dans l’inspecteur d’identité, nommez la classe SheetViewControllerdu contrôleur de vue :

    Définition du nom de classe sur SheetViewController.

  6. Définissez les points de sortie et actions nécessaires :

    Définition des points de sortie et actions requis

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

Ensuite, modifiez le SheetViewController.cs fichier et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace MacDialog
{
    public partial class SheetViewController : NSViewController
    {
        #region Private Variables
        private string _userName = "";
        private string _password = "";
        private NSViewController _presentor;
        #endregion

        #region Computed Properties
        public string UserName {
            get { return _userName; }
            set { _userName = value; }
        }

        public string Password {
            get { return _password;}
            set { _password = value;}
        }

        public NSViewController Presentor {
            get { return _presentor; }
            set { _presentor = value; }
        }
        #endregion

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

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

            // Set initial values
            NameField.StringValue = UserName;
            PasswordField.StringValue = Password;

            // Wireup events
            NameField.Changed += (sender, e) => {
                UserName = NameField.StringValue;
            };
            PasswordField.Changed += (sender, e) => {
                Password = PasswordField.StringValue;
            };
        }
        #endregion

        #region Private Methods
        private void CloseSheet() {
            Presentor.DismissViewController (this);
        }
        #endregion

        #region Custom Actions
        partial void AcceptSheet (Foundation.NSObject sender) {
            RaiseSheetAccepted();
            CloseSheet();
        }

        partial void CancelSheet (Foundation.NSObject sender) {
            RaiseSheetCanceled();
            CloseSheet();
        }
        #endregion

        #region Events
        public EventHandler SheetAccepted;

        internal void RaiseSheetAccepted() {
            if (this.SheetAccepted != null)
                this.SheetAccepted (this, EventArgs.Empty);
        }

        public EventHandler SheetCanceled;

        internal void RaiseSheetCanceled() {
            if (this.SheetCanceled != null)
                this.SheetCanceled (this, EventArgs.Empty);
        }
        #endregion
    }
}

Ensuite, modifiez le ViewController.cs fichier, modifiez la PrepareForSegue méthode et faites-la ressembler à ce qui suit :

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on the segue name
    switch (segue.Identifier) {
    case "ModalSegue":
        var dialog = segue.DestinationController as CustomDialogController;
        dialog.DialogTitle = "MacDialog";
        dialog.DialogDescription = "This is a sample dialog.";
        dialog.DialogAccepted += (s, e) => {
            Console.WriteLine ("Dialog accepted");
            DismissViewController (dialog);
        };
        dialog.Presentor = this;
        break;
    case "SheetSegue":
        var sheet = segue.DestinationController as SheetViewController;
        sheet.SheetAccepted += (s, e) => {
            Console.WriteLine ("User Name: {0} Password: {1}", sheet.UserName, sheet.Password);
        };
        sheet.Presentor = this;
        break;
    }
}

Si nous exécutons notre application et ouvrez la feuille, elle sera attachée à la fenêtre :

Exemple de feuille

Boîte de dialogue Création d’une boîte de dialogue Préférences

Avant de disposer l’affichage préférence dans le Générateur d’interface, nous devons ajouter un type segue personnalisé pour gérer le basculement des préférences. Ajoutez une nouvelle classe à votre projet et appelez-la ReplaceViewSeque. Modifiez la classe et faites-la ressembler à ce qui suit :

using System;
using AppKit;
using Foundation;

namespace MacWindows
{
    [Register("ReplaceViewSeque")]
    public class ReplaceViewSeque : NSStoryboardSegue
    {
        #region Constructors
        public ReplaceViewSeque() {

        }

        public ReplaceViewSeque (string identifier, NSObject sourceController, NSObject destinationController) : base(identifier,sourceController,destinationController) {

        }

        public ReplaceViewSeque (IntPtr handle) : base(handle) {
        }

        public ReplaceViewSeque (NSObjectFlag x) : base(x) {
        }
        #endregion

        #region Override Methods
        public override void Perform ()
        {
            // Cast the source and destination controllers
            var source = SourceController as NSViewController;
            var destination = DestinationController as NSViewController;

            // Is there a source?
            if (source == null) {
                // No, get the current key window
                var window = NSApplication.SharedApplication.KeyWindow;

                // Swap the controllers
                window.ContentViewController = destination;

                // Release memory
                window.ContentViewController?.RemoveFromParentViewController ();
            } else {
                // Swap the controllers
                source.View.Window.ContentViewController = destination;

                // Release memory
                source.RemoveFromParentViewController ();
            }

        }
        #endregion

    }

}

Une fois le segue personnalisé créé, nous pouvons ajouter une nouvelle fenêtre dans le Générateur d’interface de Xcode pour gérer nos préférences.

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

  1. Dans le Explorateur de solutions, ouvrez le Main.storyboard fichier pour modification dans le Générateur d’interface de Xcode.

  2. Faites glisser un nouveau contrôleur de fenêtre dans l’aire de conception :

    Sélectionner un contrôleur de fenêtre dans la bibliothèque

  3. Organisez la fenêtre près du concepteur de barres de menus :

    Ajout de la nouvelle fenêtre

  4. Créez des copies du contrôleur de vue attaché, car il y aura des onglets dans votre affichage de préférence :

    Ajout des contrôleurs d’affichage requis

  5. Faites glisser un nouveau contrôleur de barre d’outils à partir de la bibliothèque :

    Sélectionner un contrôleur de barre d’outils dans la bibliothèque

  6. Et déposez-la sur la fenêtre dans l’aire de conception :

    Ajout d’un nouveau contrôleur de barre d’outils

  7. Disposition de la conception de votre barre d’outils :

    Disposition de la barre d’outils

  8. Cliquez sur Le contrôle et faites glisser à partir de chaque bouton de barre d’outils vers les vues que vous avez créées ci-dessus. Sélectionnez un type de segue personnalisé :

    Définition d’un type de segue personnalisé.

  9. Sélectionnez le nouveau Segue et définissez la classe sur ReplaceViewSegue:

    Définition de la classe segue

  10. Dans le Concepteur de barres de menus sur l’aire de conception, dans le menu Application, sélectionnez Préférences..., cliquez sur le contrôle et faites glisser vers la fenêtre Préférences pour créer un affichage :

    Définition du type de segue en faisant glisser Préférences vers la fenêtre Préférences.

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

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

Exemple de fenêtre préférences affichant le mot Profil.

Pour plus d’informations sur l’utilisation de Windows et de barres d’outils, consultez notre documentation windows et barres d’outils .

Enregistrer et charger les préférences

Dans une application macOS classique, lorsque l’utilisateur apporte des modifications à l’une des préférences utilisateur de l’application, ces modifications sont enregistrées automatiquement. Le moyen le plus simple de gérer cela dans une application Xamarin.Mac consiste à créer une classe unique pour gérer toutes les préférences de l’utilisateur et la partager à l’échelle du système.

Tout d’abord, ajoutez une nouvelle AppPreferences classe au projet et héritez de NSObject. Les préférences seront conçues pour utiliser la liaison de données et le codage clé-valeur, ce qui simplifie la création et la maintenance des formulaires de préférence. Étant donné que les préférences se composent d’une petite quantité de types de données simples, utilisez l’élément intégré NSUserDefaults pour stocker et récupérer des valeurs.

Modifiez le AppPreferences.cs fichier et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    [Register("AppPreferences")]
    public class AppPreferences : NSObject
    {
        #region Computed Properties
        [Export("DefaultLanguage")]
        public int DefaultLanguage {
            get {
                var value = LoadInt ("DefaultLanguage", 0);
                return value;
            }
            set {
                WillChangeValue ("DefaultLanguage");
                SaveInt ("DefaultLanguage", value, true);
                DidChangeValue ("DefaultLanguage");
            }
        }

        [Export("SmartLinks")]
        public bool SmartLinks {
            get { return LoadBool ("SmartLinks", true); }
            set {
                WillChangeValue ("SmartLinks");
                SaveBool ("SmartLinks", value, true);
                DidChangeValue ("SmartLinks");
            }
        }

        // Define any other required user preferences in the same fashion
        ...

        [Export("EditorBackgroundColor")]
        public NSColor EditorBackgroundColor {
            get { return LoadColor("EditorBackgroundColor", NSColor.White); }
            set {
                WillChangeValue ("EditorBackgroundColor");
                SaveColor ("EditorBackgroundColor", value, true);
                DidChangeValue ("EditorBackgroundColor");
            }
        }
        #endregion

        #region Constructors
        public AppPreferences ()
        {
        }
        #endregion

        #region Public Methods
        public int LoadInt(string key, int defaultValue) {
            // Attempt to read int
            var number = NSUserDefaults.StandardUserDefaults.IntForKey(key);

            // Take action based on value
            if (number == null) {
                return defaultValue;
            } else {
                return (int)number;
            }
        }

        public void SaveInt(string key, int value, bool sync) {
            NSUserDefaults.StandardUserDefaults.SetInt(value, key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }

        public bool LoadBool(string key, bool defaultValue) {
            // Attempt to read int
            var value = NSUserDefaults.StandardUserDefaults.BoolForKey(key);

            // Take action based on value
            if (value == null) {
                return defaultValue;
            } else {
                return value;
            }
        }

        public void SaveBool(string key, bool value, bool sync) {
            NSUserDefaults.StandardUserDefaults.SetBool(value, key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }

        public string NSColorToHexString(NSColor color, bool withAlpha) {
            //Break color into pieces
            nfloat red=0, green=0, blue=0, alpha=0;
            color.GetRgba (out red, out green, out blue, out alpha);

            // Adjust to byte
            alpha *= 255;
            red *= 255;
            green *= 255;
            blue *= 255;

            //With the alpha value?
            if (withAlpha) {
                return String.Format ("#{0:X2}{1:X2}{2:X2}{3:X2}", (int)alpha, (int)red, (int)green, (int)blue);
            } else {
                return String.Format ("#{0:X2}{1:X2}{2:X2}", (int)red, (int)green, (int)blue);
            }
        }

        public NSColor NSColorFromHexString (string hexValue)
        {
            var colorString = hexValue.Replace ("#", "");
            float red, green, blue, alpha;

            // Convert color based on length
            switch (colorString.Length) {
            case 3 : // #RGB
                red = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(0, 1)), 16) / 255f;
                green = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(1, 1)), 16) / 255f;
                blue = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(2, 1)), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, 1.0f);
            case 6 : // #RRGGBB
                red = Convert.ToInt32(colorString.Substring(0, 2), 16) / 255f;
                green = Convert.ToInt32(colorString.Substring(2, 2), 16) / 255f;
                blue = Convert.ToInt32(colorString.Substring(4, 2), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, 1.0f);
            case 8 : // #AARRGGBB
                alpha = Convert.ToInt32(colorString.Substring(0, 2), 16) / 255f;
                red = Convert.ToInt32(colorString.Substring(2, 2), 16) / 255f;
                green = Convert.ToInt32(colorString.Substring(4, 2), 16) / 255f;
                blue = Convert.ToInt32(colorString.Substring(6, 2), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, alpha);
            default :
                throw new ArgumentOutOfRangeException(string.Format("Invalid color value '{0}'. It should be a hex value of the form #RBG, #RRGGBB or #AARRGGBB", hexValue));
            }
        }

        public NSColor LoadColor(string key, NSColor defaultValue) {

            // Attempt to read color
            var hex = NSUserDefaults.StandardUserDefaults.StringForKey(key);

            // Take action based on value
            if (hex == null) {
                return defaultValue;
            } else {
                return NSColorFromHexString (hex);
            }
        }

        public void SaveColor(string key, NSColor color, bool sync) {
            // Save to default
            NSUserDefaults.StandardUserDefaults.SetString(NSColorToHexString(color,true), key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }
        #endregion
    }
}

Cette classe contient quelques routines d’assistance telles que SaveInt, , SaveColorLoadInt, LoadColor, etc. pour faciliter l’utilisationNSUserDefaults. En outre, étant donné qu’il NSUserDefaults n’existe pas de moyen intégré de gérerNSColors, les méthodes et NSColorFromHexString les NSColorToHexString méthodes sont utilisées pour convertir des couleurs en chaînes hexadécimaux basées sur le web (#RRGGBBAAAA est la transparence alpha) qui peuvent être facilement stockées et récupérées.

Dans le AppDelegate.cs fichier, créez une instance de l’objet AppPreferences qui sera utilisée à l’échelle de l’application :

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

namespace SourceWriter
{
    [Register ("AppDelegate")]
    public class AppDelegate : NSApplicationDelegate
    {
        #region Computed Properties
        public int NewWindowNumber { get; set;} = -1;

        public AppPreferences Preferences { get; set; } = new AppPreferences();
        #endregion

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

        ...

Préférences de câblage aux vues de préférence

Ensuite, connectez la classe Préférence aux éléments de l’interface utilisateur dans la fenêtre de préférence et les vues créées ci-dessus. Dans le Générateur d’interface, sélectionnez un contrôleur de vue de préférence et basculez vers l’inspecteur d’identité, créez une classe personnalisée pour le contrôleur :

Inspecteur d’identité

Revenez à Visual Studio pour Mac pour synchroniser vos modifications et ouvrir la classe nouvellement créée pour modification. Faites en sorte que la classe ressemble à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    public partial class EditorPrefsController : NSViewController
    {
        #region Application Access
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Computed Properties
        [Export("Preferences")]
        public AppPreferences Preferences {
            get { return App.Preferences; }
        }
        #endregion

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

Notez que cette classe a fait deux choses ici : Tout d’abord, il existe une propriété d’assistance App pour faciliter l’accès à AppDelegate . Ensuite, la Preferences propriété expose la classe AppPreferences globale pour la liaison de données avec tous les contrôles d’interface utilisateur placés sur cette vue.

Ensuite, double-cliquez sur le fichier Storyboard pour l’ouvrir à nouveau dans le Générateur d’interface (et voir les modifications effectuées ci-dessus). Faites glisser les contrôles d’interface utilisateur nécessaires pour générer l’interface de préférences dans la vue. Pour chaque contrôle, basculez vers l’inspecteur de liaison et liez aux propriétés individuelles de la classe AppPreference :

Inspecteur de liaison

Répétez les étapes ci-dessus pour tous les panneaux (Contrôleurs d’affichage) et propriétés de préférence requises.

Application de modifications de préférence à toutes les fenêtres ouvertes

Comme indiqué ci-dessus, dans une application macOS classique, lorsque l’utilisateur apporte des modifications à l’une des préférences utilisateur de l’application, ces modifications sont enregistrées automatiquement et appliquées à toutes les fenêtres que l’utilisateur a peut-être ouvertes dans l’application.

La planification et la conception minutieuses des préférences et des fenêtres de votre application permettent à ce processus de se produire en douceur et en toute transparence pour l’utilisateur final, avec un minimum de travail de codage.

Pour toute fenêtre qui consomme les préférences d’application, ajoutez la propriété d’assistance suivante à son contrôleur de vue de contenu pour faciliter l’accès à notre AppDelegate :

#region Application Access
public static AppDelegate App {
    get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion

Ensuite, ajoutez une classe pour configurer le contenu ou le comportement en fonction des préférences de l’utilisateur :

public void ConfigureEditor() {

    // General Preferences
    TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
    TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
    ...

}

Vous devez appeler la méthode de configuration lorsque la fenêtre est ouverte pour vous assurer qu’elle est conforme aux préférences de l’utilisateur :

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

    // Configure editor from user preferences
    ConfigureEditor ();
    ...
}

Ensuite, modifiez le AppDelegate.cs fichier et ajoutez la méthode suivante pour appliquer les modifications de préférence à toutes les fenêtres ouvertes :

public void UpdateWindowPreferences() {

    // Process all open windows
    for(int n=0; n<NSApplication.SharedApplication.Windows.Length; ++n) {
        var content = NSApplication.SharedApplication.Windows[n].ContentViewController as ViewController;
        if (content != null ) {
            // Reformat all text
            content.ConfigureEditor ();
        }
    }

}

Ensuite, ajoutez une PreferenceWindowDelegate classe au projet et faites-la ressembler à ce qui suit :

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

namespace SourceWriter
{
    public class PreferenceWindowDelegate : NSWindowDelegate
    {
        #region Application Access
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Computed Properties
        public NSWindow Window { get; set;}
        #endregion

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

        }
        #endregion

        #region Override Methods
        public override bool WindowShouldClose (Foundation.NSObject sender)
        {

            // Apply any changes to open windows
            App.UpdateWindowPreferences();

            return true;
        }
        #endregion
    }
}

Cela entraîne l’envoi de modifications de préférence à toutes les fenêtres ouvertes lorsque la fenêtre de préférence se ferme.

Enfin, modifiez le contrôleur de fenêtre de préférence et ajoutez le délégué créé ci-dessus :

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    public partial class PreferenceWindowController : NSWindowController
    {
        #region Constructors
        public PreferenceWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

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

            // Initialize
            Window.Delegate = new PreferenceWindowDelegate(Window);
            Toolbar.SelectedItemIdentifier = "General";
        }
        #endregion
    }
}

Avec toutes ces modifications en place, si l’utilisateur modifie les préférences de l’application et ferme la fenêtre Préférences, les modifications sont appliquées à toutes les fenêtres ouvertes :

Exemple de fenêtre Préférences affichée avec plusieurs autres fenêtres ouvertes.

Boîte de dialogue Ouvrir

La boîte de dialogue Ouvrir offre aux utilisateurs un moyen cohérent de rechercher et d’ouvrir un élément dans une application. Pour afficher une boîte de dialogue Ouvrir dans une application Xamarin.Mac, utilisez le code suivant :

var dlg = NSOpenPanel.OpenPanel;
dlg.CanChooseFiles = true;
dlg.CanChooseDirectories = false;
dlg.AllowedFileTypes = new string[] { "txt", "html", "md", "css" };

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

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

        // Create a new window to hold the text
        var newWindowController = new MainWindowController ();
        newWindowController.Window.MakeKeyAndOrderFront (this);

        // Load the text into the window
        var window = newWindowController.Window as MainWindow;
        window.Text = File.ReadAllText(path);
        window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
        window.RepresentedUrl = url;

    }
}

Dans le code ci-dessus, nous allons ouvrir une nouvelle fenêtre de document pour afficher le contenu du fichier. Vous devez remplacer ce code par des fonctionnalités requises par votre application.

Les propriétés suivantes sont disponibles lors de l’utilisation d’un NSOpenPanel:

  • CanChooseFiles : si true l’utilisateur peut sélectionner des fichiers.
  • CanChooseDirectories : si true l’utilisateur peut sélectionner des répertoires.
  • AutoriseMultipleSelection : si true l’utilisateur peut sélectionner plusieurs fichiers à la fois.
  • ResolveAliases : si true vous sélectionnez et alias, le résout au chemin d’accès du fichier d’origine.
  • AllowedFileTypes : tableau de chaînes de types de fichiers que l’utilisateur peut sélectionner comme extension ou UTI. La valeur par défaut est null, ce qui permet à n’importe quel fichier d’être ouvert.

La RunModal () méthode affiche la boîte de dialogue Ouvrir et permet à l’utilisateur de sélectionner des fichiers ou des répertoires (comme spécifié par les propriétés) et retourne 1 si l’utilisateur clique sur le bouton Ouvrir .

La boîte de dialogue Ouvrir retourne les fichiers ou répertoires sélectionnés de l’utilisateur en tant que tableau d’URL dans la URL propriété.

Si nous exécutons le programme et sélectionnez l’élément Ouvrir... dans le menu Fichier , les éléments suivants s’affichent :

Boîte de dialogue Ouverte

Boîtes de dialogue Imprimer et Mise en page

macOS fournit des boîtes de dialogue standard d’impression et de mise en page que votre application peut afficher afin que les utilisateurs puissent avoir une expérience d’impression cohérente dans chaque application qu’ils utilisent.

Le code suivant affiche la boîte de dialogue d’impression standard :

public bool ShowPrintAsSheet { get; set;} = true;
...

[Export ("showPrinter:")]
void ShowDocument (NSObject sender) {
    var dlg = new NSPrintPanel();

    // Display the print dialog as dialog box
    if (ShowPrintAsSheet) {
        dlg.BeginSheet(new NSPrintInfo(),this,this,null,new IntPtr());
    } else {
        if (dlg.RunModalWithPrintInfo(new NSPrintInfo()) == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to print the document here...",
                MessageText = "Print Document",
            };
            alert.RunModal ();
        }
    }
}

Si nous définissons la ShowPrintAsSheet propriété falsesur , exécutez l’application et affichez la boîte de dialogue d’impression, les éléments suivants s’affichent :

Boîte de dialogue Imprimer

Si la propriété trueest ShowPrintAsSheet définie sur , exécutez l’application et affichez la boîte de dialogue d’impression, les éléments suivants s’affichent :

Feuille d’impression

Le code suivant affiche la boîte de dialogue Mise en page :

[Export ("showLayout:")]
void ShowLayout (NSObject sender) {
    var dlg = new NSPageLayout();

    // Display the print dialog as dialog box
    if (ShowPrintAsSheet) {
        dlg.BeginSheet (new NSPrintInfo (), this);
    } else {
        if (dlg.RunModal () == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to print the document here...",
                MessageText = "Print Document",
            };
            alert.RunModal ();
        }
    }
}

Si nous définissons la ShowPrintAsSheet propriété falsesur , exécutez l’application et affichez la boîte de dialogue mise en page d’impression, les éléments suivants s’affichent :

Boîte de dialogue Mise en page

Si définissez la ShowPrintAsSheet propriété truesur , exécutez l’application et affichez la boîte de dialogue mise en page d’impression, les éléments suivants s’affichent :

Feuille de configuration d’une page

Pour plus d’informations sur l’utilisation des boîtes de dialogue d’impression et de mise en page, consultez la documentation NSPrintPanel et NSPageLayout d’Apple.

Boîte de dialogue Enregistrer

La boîte de dialogue Enregistrer offre aux utilisateurs un moyen cohérent d’enregistrer un élément dans une application.

Le code suivant affiche la boîte de dialogue Enregistrer standard :

public bool ShowSaveAsSheet { get; set;} = true;
...

[Export("saveDocumentAs:")]
void ShowSaveAs (NSObject sender)
{
    var dlg = new NSSavePanel ();
    dlg.Title = "Save Text File";
    dlg.AllowedFileTypes = new string[] { "txt", "html", "md", "css" };

    if (ShowSaveAsSheet) {
        dlg.BeginSheet(mainWindowController.Window,(result) => {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        });
    } else {
        if (dlg.RunModal () == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        }
    }

}

La AllowedFileTypes propriété est un tableau de chaînes de types de fichiers que l’utilisateur peut sélectionner pour enregistrer le fichier sous. Le type de fichier peut être spécifié en tant qu’extension ou UTI. La valeur par défaut est null, ce qui permet à n’importe quel type de fichier d’être utilisé.

Si nous définissons la ShowSaveAsSheet propriété falsesur , exécutez l’application et sélectionnez Enregistrer sous... dans le menu Fichier , les éléments suivants s’affichent :

Boîte de dialogue Enregistrer

L’utilisateur peut développer la boîte de dialogue :

Boîte de dialogue Enregistrer développée

Si nous définissons la ShowSaveAsSheet propriété truesur , exécutez l’application et sélectionnez Enregistrer sous... dans le menu Fichier , les éléments suivants s’affichent :

Une feuille d’enregistrement

L’utilisateur peut développer la boîte de dialogue :

Une feuille d’enregistrement développée

Pour plus d’informations sur l’utilisation de la boîte de dialogue Enregistrer, consultez la documentation NSSavePanel d’Apple.

Résumé

Cet article a examiné en détail l’utilisation des fenêtres modales, des feuilles et des boîtes de dialogue système standard dans une application Xamarin.Mac. Nous avons vu les différents types et utilisations des fenêtres modales, des feuilles et des dialogues, comment créer et gérer des fenêtres modales et des feuilles dans le Générateur d’interface de Xcode et comment utiliser les fenêtres modales, les feuilles et les dialogues dans le code C#.