Partager via


Menus dans Xamarin.Mac

Cet article traite de l’utilisation des menus dans une application Xamarin.Mac. Il décrit la création et la maintenance des menus et des éléments de menu dans Xcode et Interface Builder et leur utilisation par programmation.

Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes menus Cocoa 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 barres de menus, menus et éléments de menu (ou éventuellement les créer directement dans le code C#).

Les menus font partie intégrante de l’expérience utilisateur d’une application Mac et apparaissent généralement dans différentes parties de l’interface utilisateur :

  • Barre de menus de l’application : il s’agit du menu principal qui apparaît en haut de l’écran pour chaque application Mac.
  • Menus contextuels : ceux-ci s’affichent lorsque l’utilisateur clique avec le bouton droit ou contrôle sur un élément dans une fenêtre.
  • Barre d’état : il s’agit de la zone située à l’extrême droite de la barre de menus de l’application qui apparaît en haut de l’écran (à gauche de l’horloge de la barre de menus) et augmente à gauche à mesure que les éléments sont ajoutés à celui-ci.
  • Menu Dock : menu de chaque application dans le dock qui s’affiche lorsque l’utilisateur clique avec le bouton droit ou clique sur l’icône de l’application, ou lorsque l’utilisateur clique sur l’icône et conserve le bouton de la souris vers le bas.
  • Bouton contextuel et listes déroulantes : un bouton contextuel affiche un élément sélectionné et présente une liste d’options à sélectionner lorsqu’il clique sur l’utilisateur. Une liste déroulante est un type de bouton contextuel généralement utilisé pour sélectionner des commandes spécifiques au contexte de la tâche actuelle. Les deux peuvent apparaître n’importe où dans une fenêtre.

Exemple de menu

Dans cet article, nous allons aborder les principes fondamentaux de l’utilisation des barres de menus, menus et éléments de menu Cocoa 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 attributs utilisés pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.

Barre de menus de l’application

Contrairement aux applications s’exécutant sur le système d’exploitation Windows où chaque fenêtre peut avoir sa propre barre de menus attachée, chaque application s’exécutant sur macOS a une barre de menus unique qui s’exécute le long de l’écran utilisé pour chaque fenêtre de cette application :

Barre de menus

Les éléments de cette barre de menus sont activés ou désactivés en fonction du contexte ou de l’état actuel de l’application et de son interface utilisateur à un moment donné. Par exemple : si l’utilisateur sélectionne un champ de texte, les éléments du menu Édition sont activés, tels que Copier et Couper.

Selon Apple et par défaut, toutes les applications macOS ont un ensemble standard de menus et d’éléments de menu qui apparaissent dans la barre de menus de l’application :

  • Menu Apple : ce menu permet d’accéder aux éléments à l’échelle du système disponibles pour l’utilisateur à tout moment, quelle que soit l’application en cours d’exécution. Ces éléments ne peuvent pas être modifiés par le développeur.
  • Menu De l’application : ce menu affiche le nom de l’application en gras et aide l’utilisateur à identifier l’application en cours d’exécution. Il contient des éléments qui s’appliquent à l’application dans son ensemble et qui ne sont pas un document ou un processus donné, tels que la fermeture de l’application.
  • Menu Fichier : éléments utilisés pour créer, ouvrir ou enregistrer des documents avec utilisant votre application. Si votre application n’est pas basée sur un document, ce menu peut être renommé ou supprimé.
  • Menu Modifier : contient des commandes telles que Couper, Copier et Coller qui sont utilisées pour modifier ou modifier des éléments dans l’interface utilisateur de l’application.
  • Menu Format : si l’application fonctionne avec du texte, ce menu contient des commandes pour ajuster la mise en forme de ce texte.
  • Menu Affichage : contient des commandes qui affectent l’affichage du contenu (affiché) dans l’interface utilisateur de l’application.
  • Menus spécifiques à l’application : il s’agit de menus spécifiques à votre application (par exemple, un menu signets pour un navigateur web). Ils doivent apparaître entre les menus Affichage et Fenêtre dans la barre.
  • Menu Fenêtre : contient des commandes permettant d’utiliser des fenêtres dans votre application, ainsi qu’une liste de fenêtres ouvertes actuelles.
  • Menu d’aide : si votre application fournit de l’aide à l’écran, le menu Aide doit être le menu le plus à droite de la barre.

Pour plus d’informations sur la barre de menus de l’application et les menus standard et les éléments de menu, consultez les instructions relatives à l’interface humaine d’Apple.

Barre de menus de l’application par défaut

Chaque fois que vous créez un projet Xamarin.Mac, vous obtenez automatiquement une barre de menus d’application standard et par défaut qui contient les éléments typiques qu’une application macOS aurait normalement (comme indiqué dans la section ci-dessus). La barre de menus par défaut de votre application est définie dans le fichier Main.storyboard (ainsi que le reste de l’interface utilisateur de votre application) sous le projet dans le Panneau Solution :

Sélectionner le storyboard principal

Double-cliquez sur le fichier Main.storyboard pour l’ouvrir pour la modifier dans le Générateur d’interface de Xcode et vous serez présenté avec l’interface de l’éditeur de menu :

Modification de l’interface utilisateur dans Xcode, montrant le storyboard point principal.

À partir de là, nous pouvons cliquer sur des éléments tels que l’élément de menu Ouvrir dans le menu Fichier et modifier ou ajuster ses propriétés dans l’inspecteur d’attributs :

Modification des attributs d’un menu

Nous allons nous familiariser avec l’ajout, la modification et la suppression de menus et d’éléments plus loin dans cet article. Pour l’instant, nous voulons simplement voir quels menus et éléments de menu sont disponibles par défaut et comment ils ont été automatiquement exposés au code via un ensemble de points de vente et d’actions prédéfinis (pour plus d’informations, consultez notre documentation Sur les points de vente et actions ).

Par exemple, si nous cliquez sur l’inspecteur d’Connecter ion pour l’élément de menu Ouvrir, nous pouvons voir qu’il est automatiquement câblé à l’action openDocument: :

Affichage de l’action jointe

Si vous sélectionnez le premier répondeur dans la hiérarchie d’interface et faites défiler vers le bas dans l’inspecteur Connecter ion, et vous verrez la définition de l’action openDocument: à laquelle l’élément de menu Ouvrir est attaché (ainsi que plusieurs autres actions par défaut pour l’application qui sont et ne sont pas automatiquement câblées aux contrôles) :

Affichage de toutes les actions jointes

Pourquoi est-ce important ? Dans la section suivante, vous verrez comment ces actions définies automatiquement fonctionnent avec d’autres éléments d’interface utilisateur Cocoa pour activer et désactiver automatiquement les éléments de menu, ainsi que fournir des fonctionnalités intégrées pour les éléments.

Plus tard, nous allons utiliser ces actions intégrées pour activer et désactiver des éléments à partir du code et fournir nos propres fonctionnalités lorsqu’elles sont sélectionnées.

Fonctionnalités de menu intégrées

Si vous avez exécuté une application Xamarin.Mac nouvellement créée avant d’ajouter des éléments ou du code d’interface utilisateur, vous remarquerez que certains éléments sont automatiquement câblés et activés pour vous (avec une fonctionnalité complète intégrée), par exemple l’élément quitter l’application :

Élément de menu activé

Bien que d’autres éléments de menu, tels que Couper, Copier et Coller , ne soient pas :

Éléments de menu désactivés

Arrêtons l’application et double-cliquez sur le fichier Main.storyboard dans le Panneau Solution pour l’ouvrir pour modification dans le Générateur d’interface de Xcode. Ensuite, faites glisser un affichage texte de la bibliothèque vers le contrôleur d’affichage de la fenêtre dans l’Éditeur d’interface :

Sélection d’une vue de texte dans la bibliothèque

Dans l’Éditeur de contraintes, nous allons épingler l’affichage texte aux bords de la fenêtre et le définir là où elle augmente et se réduit avec la fenêtre en cliquant sur les quatre faisceaux d’I rouges en haut de l’éditeur et en cliquant sur le bouton Ajouter 4 contraintes :

Modification des contraintes

Enregistrez vos modifications dans la conception de l’interface utilisateur et revenez au Visual Studio pour Mac pour synchroniser les modifications avec votre projet Xamarin.Mac. À présent, démarrez l’application, tapez du texte dans l’affichage texte, sélectionnez-le, puis ouvrez le menu Modifier :

Les éléments de menu sont automatiquement activés/désactivés

Notez que les éléments Couper, Copier et Coller sont automatiquement activés et entièrement fonctionnels, sans écrire une seule ligne de code.

Comment cela se fait-il ? N’oubliez pas les actions prédéfinies intégrées qui sont connectées aux éléments de menu par défaut (comme indiqué ci-dessus), la plupart des éléments de l’interface utilisateur Cocoa qui font partie de macOS ont intégré des crochets à des actions spécifiques (par exemple copy:). Par conséquent, lorsqu’elles sont ajoutées à une fenêtre, active et sélectionnée, l’élément de menu ou les éléments correspondants attachés à cette action sont automatiquement activés. Si l’utilisateur sélectionne cet élément de menu, la fonctionnalité intégrée à l’élément d’interface utilisateur est appelée et exécutée, sans intervention du développeur.

Activation et désactivation des menus et des éléments

Par défaut, chaque fois qu’un événement utilisateur se produit, NSMenu active et désactive automatiquement chaque menu et élément de menu visibles en fonction du contexte de l’application. Il existe trois façons d’activer/désactiver un élément :

  • Activation automatique du menu : un élément de menu est activé si NSMenu un objet approprié répond à l’action à laquelle l’élément est connecté. Par exemple, la vue de texte ci-dessus qui avait un hook intégré à l’action copy: .
  • Actions personnalisées et validateMenuItem : pour tous les éléments de menu liés à une action personnalisée de contrôleur de fenêtre ou d’affichage, vous pouvez ajouter l’action validateMenuItem: et activer ou désactiver manuellement les éléments de menu.
  • Menu manuel activé : vous définissez manuellement la Enabled propriété de chaque NSMenuItem élément pour activer ou désactiver chaque élément dans un menu individuellement.

Pour choisir un système, définissez la AutoEnablesItems propriété d’un NSMenu. true est automatique (comportement par défaut) et false est manuel.

Important

Si vous choisissez d’utiliser le menu manuel activé, aucun des éléments de menu, même ceux contrôlés par les classes AppKit comme NSTextView, sont mis à jour automatiquement. Vous serez responsable de l’activation et de la désactivation de tous les éléments par le code.

Utilisation de validateMenuItem

Comme indiqué ci-dessus, pour tout élément de menu lié à une action personnalisée du contrôleur de fenêtre ou d’affichage, vous pouvez ajouter l’action validateMenuItem: et activer ou désactiver manuellement les éléments de menu.

Dans l’exemple suivant, la Tag propriété sera utilisée pour déterminer le type d’élément de menu qui sera activé/désactivé par l’action en fonction de l’état validateMenuItem: du texte sélectionné dans un NSTextView. La Tag propriété a été définie dans Le Générateur d’interface pour chaque élément de menu :

Définition de la propriété Tag

Et le code suivant ajouté au contrôleur de vue :

[Action("validateMenuItem:")]
public bool ValidateMenuItem (NSMenuItem item) {

    // Take action based on the menu item type
    // (As specified in its Tag)
    switch (item.Tag) {
    case 1:
        // Wrap menu items should only be available if
        // a range of text is selected
        return (TextEditor.SelectedRange.Length > 0);
    case 2:
        // Quote menu items should only be available if
        // a range is NOT selected.
        return (TextEditor.SelectedRange.Length == 0);
    }

    return true;
}

Lorsque ce code est exécuté et qu’aucun texte n’est sélectionné dans le NSTextViewcode, les deux éléments de menu encapsulés sont désactivés (même s’ils sont câblés aux actions sur le contrôleur d’affichage) :

Affichage des éléments désactivés

Si une section de texte est sélectionnée et que le menu est rouvert, les deux éléments de menu encapsulés sont disponibles :

Affichage des éléments activés

Activation et réponse aux éléments de menu dans le code

Comme nous l’avons vu ci-dessus, simplement en ajoutant des éléments d’interface utilisateur Cocoa spécifiques à notre conception d’interface utilisateur (par exemple, un champ de texte), plusieurs éléments de menu par défaut sont activés et fonctionnent automatiquement, sans avoir à écrire de code. Examinons ensuite l’ajout de notre propre code C# à notre projet Xamarin.Mac pour activer un élément de menu et fournir des fonctionnalités lorsque l’utilisateur le sélectionne.

Par exemple, supposons que l’utilisateur puisse utiliser l’élément Ouvrir dans le menu Fichier pour sélectionner un dossier. Étant donné que nous voulons qu’il s’agit d’une fonction à l’échelle de l’application et non limitée à un élément de fenêtre ou d’interface utilisateur donné, nous allons ajouter le code pour le gérer à notre délégué d’application.

Dans le panneau Solution, double-cliquez sur le AppDelegate.CS fichier pour l’ouvrir pour modification :

Sélection du délégué d’application

Ajoutez le code suivant à la méthode DidFinishLaunching :

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

    if (dlg.RunModal () == 1) {
        var alert = new NSAlert () {
            AlertStyle = NSAlertStyle.Informational,
            InformativeText = "At this point we should do something with the folder that the user just selected in the Open File Dialog box...",
            MessageText = "Folder Selected"
        };
        alert.RunModal ();
    }
}

Nous allons exécuter l’application maintenant et ouvrir le menu Fichier :

Menu Fichier

Notez que l’élément de menu Ouvrir est désormais activé. Si nous le sélectionnons, la boîte de dialogue d’ouverture s’affiche :

Boîte de dialogue Ouvrir

Si nous cliquez sur le bouton Ouvrir , notre message d’alerte s’affiche :

Exemple de message de boîte de dialogue

La ligne clé ici était [Export ("openDocument:")], il indique NSMenu que notre AppDelegate a une méthode void OpenDialog (NSObject sender) qui répond à l’action openDocument: . Si vous vous souvenez de ce qui précède, l’élément de menu Ouvrir est automatiquement câblé à cette action par défaut dans le Générateur d’interface :

Affichage des actions jointes

Examinons ensuite la création de notre propre menu, des éléments de menu et des actions et répondons-y dans le code.

Utilisation du menu récent ouvert

Par défaut, le menu Fichier contient un élément Open Recent qui effectue le suivi des derniers fichiers ouverts par l’utilisateur avec votre application. Si vous créez une NSDocument application Xamarin.Mac basée, ce menu sera géré automatiquement pour vous. Pour tout autre type d’application Xamarin.Mac, vous serez chargé de gérer et de répondre manuellement à cet élément de menu.

Pour gérer manuellement le menu Ouvrir récent , vous devez d’abord l’informer qu’un nouveau fichier a été ouvert ou enregistré à l’aide des éléments suivants :

// Add document to the Open Recent menu
NSDocumentController.SharedDocumentController.NoteNewRecentDocumentURL(url);

Même si votre application n’utilise NSDocumentspas , vous utilisez toujours le NSDocumentController menu Ouvrir récent en envoyant un NSUrl emplacement du fichier à la NoteNewRecentDocumentURL méthode du SharedDocumentControllerfichier .

Ensuite, vous devez remplacer la OpenFile méthode du délégué d’application pour ouvrir un fichier que l’utilisateur sélectionne dans le menu Ouvrir récent . Par exemple :

public override bool OpenFile (NSApplication sender, string filename)
{
    // Trap all errors
    try {
        filename = filename.Replace (" ", "%20");
        var url = new NSUrl ("file://"+filename);
        return OpenFile(url);
    } catch {
        return false;
    }
}

Retourne true si le fichier peut être ouvert, sinon false un avertissement intégré s’affiche à l’utilisateur que le fichier n’a pas pu être ouvert.

Étant donné que le nom de fichier et le chemin d’accès retournés à partir du menu Ouvrir récent peuvent inclure un espace, nous devons échapper correctement à ce caractère avant de créer une NSUrl erreur ou nous obtiendrons une erreur. Nous procédons ainsi avec le code suivant :

filename = filename.Replace (" ", "%20");

Enfin, nous créons un NSUrl point qui pointe vers le fichier et utilisons une méthode d’assistance dans le délégué de l’application pour ouvrir une nouvelle fenêtre et charger le fichier dans celui-ci :

var url = new NSUrl ("file://"+filename);
return OpenFile(url);

Pour rassembler tous les éléments, examinons un exemple d’implémentation dans un fichier AppDelegate.cs :

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

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

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override void DidFinishLaunching (NSNotification notification)
        {
            // Insert code here to initialize your application
        }

        public override void WillTerminate (NSNotification notification)
        {
            // Insert code here to tear down your application
        }

        public override bool OpenFile (NSApplication sender, string filename)
        {
            // Trap all errors
            try {
                filename = filename.Replace (" ", "%20");
                var url = new NSUrl ("file://"+filename);
                return OpenFile(url);
            } catch {
                return false;
            }
        }
        #endregion

        #region Private Methods
        private bool OpenFile(NSUrl url) {
            var good = false;

            // Trap all errors
            try {
                var path = url.Path;

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

                // 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.SetLanguageFromPath(path);
                viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
                viewController.View.Window.RepresentedUrl = url;

                // Add document to the Open Recent menu
                NSDocumentController.SharedDocumentController.NoteNewRecentDocumentURL(url);

                // Make as successful
                good = true;
            } catch {
                // Mark as bad file on error
                good = false;
            }

            // Return results
            return good;
        }
        #endregion

        #region actions
        [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) {
                    // Open the document in a new window
                    OpenFile (url);
                }
            }
        }
        #endregion
    }
}

En fonction des exigences de votre application, vous ne souhaiterez peut-être pas que l’utilisateur ouvre le même fichier dans plusieurs fenêtres en même temps. Dans notre exemple d’application, si l’utilisateur choisit un fichier déjà ouvert (à partir des éléments de menu Ouvrir récent ou Open.. ), la fenêtre qui contient le fichier est mise en avant.

Pour ce faire, nous avons utilisé le code suivant dans notre méthode d’assistance :

var path = url.Path;

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

Nous avons conçu notre ViewController classe pour contenir le chemin d’accès au fichier dans sa Path propriété. Ensuite, nous parcourons toutes les fenêtres actuellement ouvertes dans l’application. Si le fichier est déjà ouvert dans l’une des fenêtres, il est placé devant toutes les autres fenêtres à l’aide de :

NSApplication.SharedApplication.Windows[n].MakeKeyAndOrderFront(this);

Si aucune correspondance n’est trouvée, une nouvelle fenêtre est ouverte avec le fichier chargé et le fichier est noté dans le menu Ouvrir récent :

// 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.SetLanguageFromPath(path);
viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
viewController.View.Window.RepresentedUrl = url;

// Add document to the Open Recent menu
NSDocumentController.SharedDocumentController.NoteNewRecentDocumentURL(url);

Utilisation des actions de fenêtre personnalisées

Tout comme les actions intégrées de First Responder qui sont pré-câblées aux éléments de menu standard, vous pouvez créer de nouvelles actions personnalisées et les connecter à des éléments de menu dans le Générateur d’interface.

Tout d’abord, définissez une action personnalisée sur l’un des contrôleurs de fenêtre de votre application. Par exemple :

[Action("defineKeyword:")]
public void defineKeyword (NSObject sender) {
    // Preform some action when the menu is selected
    Console.WriteLine ("Request to define keyword");
}

Ensuite, double-cliquez sur le fichier storyboard de l’application dans le Panneau Solution pour l’ouvrir pour modification dans le Générateur d’interface de Xcode. Sélectionnez le premier répondeur sous la scène de l’application, puis basculez vers l’inspecteur d’attributs :

Inspecteur d’attributs

Cliquez sur le + bouton en bas de l’inspecteur d’attributs pour ajouter une nouvelle action personnalisée :

Ajout d’une nouvelle action

Donnez-lui le même nom que l’action personnalisée que vous avez créée sur votre contrôleur de fenêtre :

Modification du nom de l’action

Cliquez sur le contrôle et faites glisser d’un élément de menu vers le premier répondeur sous la scène d’application. Dans la liste contextuelle, sélectionnez la nouvelle action que vous venez de créer (defineKeyword: dans cet exemple) :

Attachement d’une action

Enregistrez les modifications dans le storyboard et revenez à Visual Studio pour Mac pour synchroniser les modifications. Si vous exécutez l’application, l’élément de menu auquel vous avez connecté l’action personnalisée sera automatiquement activé/désactivé (en fonction de la fenêtre avec l’action ouverte) et la sélection de l’élément de menu déclenche l’action :

Test de la nouvelle action

Ajout, modification et suppression de menus

Comme nous l’avons vu dans les sections précédentes, une application Xamarin.Mac est fournie avec un nombre prédéfini de menus par défaut et d’éléments de menu auxquels des contrôles d’interface utilisateur spécifiques activent et répondent automatiquement. Nous avons également vu comment ajouter du code à notre application qui permettra également de répondre à ces éléments par défaut.

Dans cette section, nous allons examiner la suppression des éléments de menu dont nous n’avons pas besoin, réorganiser les menus et ajouter de nouveaux menus, éléments de menu et actions.

Double-cliquez sur le fichier Main.storyboard dans le Panneau Solution pour l’ouvrir pour modification :

Double-cliquez sur le fichier storyboard pour modifier l’interface utilisateur dans Xcode.

Pour notre application Xamarin.Mac spécifique, nous n’allons pas utiliser le menu Affichage par défaut afin que nous allons le supprimer. Dans la hiérarchie d’interface, sélectionnez l’élément de menu Affichage qui fait partie de la barre de menus principale :

Sélection de l’élément de menu Affichage

Appuyez sur Supprimer ou rétrospace pour supprimer le menu. Ensuite, nous n’allons pas utiliser tous les éléments dans le menu Format et nous voulons déplacer les éléments que nous allons utiliser sous les sous-menus. Dans la hiérarchie d’interface, sélectionnez les éléments de menu suivants :

Mise en surbrillance de plusieurs éléments

Faites glisser les éléments sous le menu parent à partir du sous-menu où ils sont actuellement :

Faire glisser des éléments de menu vers le menu parent

Votre menu doit maintenant ressembler à ceci :

Éléments dans le nouvel emplacement

Ensuite, faites glisser le sous-menu Texte à partir du menu Format et placez-le dans la barre de menus principale entre les menus Format et Fenêtre :

Menu Texte

Revenons sous le menu Format et supprimez l’élément de sous-menu Police . Ensuite, sélectionnez le menu Format et renommez-le « Police » :

Menu Police

Ensuite, nous allons créer un menu personnalisé d’expressions prédéfinies qui seront automatiquement ajoutées au texte dans l’affichage texte lorsqu’elles sont sélectionnées. Dans la zone de recherche située en bas de l’inspecteur de bibliothèque, tapez « menu ». Cela facilite la recherche et l’utilisation de tous les éléments de l’interface utilisateur du menu :

Inspecteur de bibliothèque

À présent, procédons comme suit pour créer notre menu :

  1. Faites glisser un élément de menu de l’inspecteur de bibliothèque vers la barre de menus entre les menus Texte et Fenêtre :

    Sélection d’un nouvel élément de menu dans la bibliothèque

  2. Renommez l’élément « Phrases » :

    Définition du nom du menu

  3. Ensuite, faites glisser un menu à partir de l’inspecteur de bibliothèque :

    Sélection d’un menu dans la bibliothèque

  4. Déposez puis menu dans le nouvel élément de menu que nous venons de créer et remplacez son nom par « Phrases » :

    Modification du nom du menu

  5. Nous allons maintenant renommer les trois éléments de menu par défaut « Adresse », « Date » et « Salutation » :

    Menu Expressions

  6. Ajoutons un quatrième élément de menu en faisant glisser un élément de menu à partir de l’inspecteur de bibliothèque et en l’appelant « Signature » :

    Modification du nom de l’élément de menu

  7. Enregistrez les modifications apportées à la barre de menus.

Nous allons maintenant créer un ensemble d’actions personnalisées afin que nos nouveaux éléments de menu soient exposés au code C#. Dans Xcode, nous allons basculer vers la vue Assistant :

Création des actions requises

Procédons comme suit :

  1. Faites glisser le contrôle de l’élément de menu Adresse vers le fichier AppDelegate.h .

  2. Basculez le type d’Connecter ion en Action :

    Sélection du type d’action

  3. Entrez un nom de « phraseAddress » et appuyez sur le bouton Connecter pour créer l’action :

    Configuration de l’action en entrant un nom.

  4. Répétez les étapes ci-dessus pour les éléments de menu Date, Salutation et Signature :

    Actions terminées

  5. Enregistrez les modifications apportées à la barre de menus.

Ensuite, nous devons créer une sortie pour notre affichage texte afin de pouvoir ajuster son contenu à partir du code. Sélectionnez le fichier ViewController.h dans l’Éditeur Assistant et créez une sortie appelée documentText:

Création d’une sortie

Revenez à Visual Studio pour Mac pour synchroniser les modifications de Xcode. Modifiez ensuite le fichier ViewController.cs et faites-le ressembler à ce qui suit :

using System;

using AppKit;
using Foundation;

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

        #region Computed Properties
        public override NSObject RepresentedObject {
            get {
                return base.RepresentedObject;
            }
            set {
                base.RepresentedObject = value;
                // Update the view, if already loaded.
            }
        }

        public string Text {
            get { return documentText.Value; }
            set { documentText.Value = value; }
        }
        #endregion

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

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

            // Do any additional setup after loading the view.
        }

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

            App.textEditor = this;
        }

        public override void ViewWillDisappear ()
        {
            base.ViewDidDisappear ();

            App.textEditor = null;
        }
        #endregion
    }
}

Cela expose le texte de notre affichage texte en dehors de la ViewController classe et informe le délégué de l’application lorsque la fenêtre gagne ou perd le focus. Modifiez maintenant le fichier AppDelegate.cs et faites-le ressembler à ce qui suit :

using AppKit;
using Foundation;
using System;

namespace MacMenus
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : NSApplicationDelegate
    {
        #region Computed Properties
        public ViewController textEditor { get; set;} = null;
        #endregion

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override void DidFinishLaunching (NSNotification notification)
        {
            // Insert code here to initialize your application
        }

        public override void WillTerminate (NSNotification notification)
        {
            // Insert code here to tear down your application
        }
        #endregion

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

            if (dlg.RunModal () == 1) {
                var alert = new NSAlert () {
                    AlertStyle = NSAlertStyle.Informational,
                    InformativeText = "At this point we should do something with the folder that the user just selected in the Open File Dialog box...",
                    MessageText = "Folder Selected"
                };
                alert.RunModal ();
            }
        }

        partial void phrasesAddress (Foundation.NSObject sender) {

            textEditor.Text += "Xamarin HQ\n394 Pacific Ave, 4th Floor\nSan Francisco CA 94111\n\n";
        }

        partial void phrasesDate (Foundation.NSObject sender) {

            textEditor.Text += DateTime.Now.ToString("D");
        }

        partial void phrasesGreeting (Foundation.NSObject sender) {

            textEditor.Text += "Dear Sirs,\n\n";
        }

        partial void phrasesSignature (Foundation.NSObject sender) {

            textEditor.Text += "Sincerely,\n\nKevin Mullins\nXamarin,Inc.\n";
        }
        #endregion
    }
}

Ici, nous avons effectué la AppDelegate classe partielle afin que nous puissions utiliser les actions et les sorties que nous avons définies dans Le Générateur d’interface. Nous exposons également une textEditor fenêtre pour suivre la fenêtre actuellement en cours de focus.

Les méthodes suivantes permettent de gérer nos éléments de menu et de menu personnalisés :

partial void phrasesAddress (Foundation.NSObject sender) {

    if (textEditor == null) return;
    textEditor.Text += "Xamarin HQ\n394 Pacific Ave, 4th Floor\nSan Francisco CA 94111\n\n";
}

partial void phrasesDate (Foundation.NSObject sender) {

    if (textEditor == null) return;
    textEditor.Text += DateTime.Now.ToString("D");
}

partial void phrasesGreeting (Foundation.NSObject sender) {

    if (textEditor == null) return;
    textEditor.Text += "Dear Sirs,\n\n";
}

partial void phrasesSignature (Foundation.NSObject sender) {

    if (textEditor == null) return;
    textEditor.Text += "Sincerely,\n\nKevin Mullins\nXamarin,Inc.\n";
}

À présent, si nous exécutons notre application, tous les éléments du menu Phrase seront actifs et ajouteront l’expression donner à l’affichage texte lorsqu’ils sont sélectionnés :

Exemple de l’application en cours d’exécution

Maintenant que nous avons les principes de base de l’utilisation de la barre de menus de l’application vers le bas, examinons la création d’un menu contextuel personnalisé.

Création de menus à partir du code

Outre la création de menus et d’éléments de menu avec le Générateur d’interface de Xcode, il peut arriver qu’une application Xamarin.Mac crée, modifie ou supprime un menu, un sous-menu ou un élément de menu du code.

Dans l’exemple suivant, une classe est créée pour contenir les informations sur les éléments de menu et les sous-menus qui seront créés dynamiquement à la volée :

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace AppKit.TextKit.Formatter
{
    public class LanguageFormatCommand : NSObject
    {
        #region Computed Properties
        public string Title { get; set; } = "";
        public string Prefix { get; set; } = "";
        public string Postfix { get; set; } = "";
        public List<LanguageFormatCommand> SubCommands { get; set; } = new List<LanguageFormatCommand>();
        #endregion

        #region Constructors
        public LanguageFormatCommand () {

        }

        public LanguageFormatCommand (string title)
        {
            // Initialize
            this.Title = title;
        }

        public LanguageFormatCommand (string title, string prefix)
        {
            // Initialize
            this.Title = title;
            this.Prefix = prefix;
        }

        public LanguageFormatCommand (string title, string prefix, string postfix)
        {
            // Initialize
            this.Title = title;
            this.Prefix = prefix;
            this.Postfix = postfix;
        }
        #endregion
    }
}

Ajout de menus et d’éléments

Avec cette classe définie, la routine suivante analyse une collection d’objets et génère de manière récursive de LanguageFormatCommandnouveaux menus et éléments de menu en les ajoutant au bas du menu existant (créé dans Interface Builder) qui a été passé :

private void AssembleMenu(NSMenu menu, List<LanguageFormatCommand> commands) {
    NSMenuItem menuItem;

    // Add any formatting commands to the Formatting menu
    foreach (LanguageFormatCommand command in commands) {
        // Add separator or item?
        if (command.Title == "") {
            menuItem = NSMenuItem.SeparatorItem;
        } else {
            menuItem = new NSMenuItem (command.Title);

            // Submenu?
            if (command.SubCommands.Count > 0) {
                // Yes, populate submenu
                menuItem.Submenu = new NSMenu (command.Title);
                AssembleMenu (menuItem.Submenu, command.SubCommands);
            } else {
                // No, add normal menu item
                menuItem.Activated += (sender, e) => {
                    // Apply the command on the selected text
                    TextEditor.PerformFormattingCommand (command);
                };
            }
        }
        menu.AddItem (menuItem);
    }
}

Pour tout LanguageFormatCommand objet qui a une propriété vide Title , cette routine crée un élément de menu Séparateur (une ligne grise mince) entre les sections de menu :

menuItem = NSMenuItem.SeparatorItem;

Si un titre est fourni, un nouvel élément de menu avec ce titre est créé :

menuItem = new NSMenuItem (command.Title);

Si l’objet LanguageFormatCommand contient des objets enfants LanguageFormatCommand , un sous-menu est créé et la AssembleMenu méthode est récursivement appelée pour générer ce menu :

menuItem.Submenu = new NSMenu (command.Title);
AssembleMenu (menuItem.Submenu, command.SubCommands);

Pour tout nouvel élément de menu qui n’a pas de sous-menus, le code est ajouté pour gérer l’élément de menu sélectionné par l’utilisateur :

menuItem.Activated += (sender, e) => {
    // Do something when the menu item is selected
    ...
};

Test de la création du menu

Avec tout le code ci-dessus en place, si la collection d’objets LanguageFormatCommand suivante a été créée :

// Define formatting commands
FormattingCommands.Add(new LanguageFormatCommand("Strong","**","**"));
FormattingCommands.Add(new LanguageFormatCommand("Emphasize","_","_"));
FormattingCommands.Add(new LanguageFormatCommand("Inline Code","`","`"));
FormattingCommands.Add(new LanguageFormatCommand("Code Block","```\n","\n```"));
FormattingCommands.Add(new LanguageFormatCommand("Comment","<!--","-->"));
FormattingCommands.Add (new LanguageFormatCommand ());
FormattingCommands.Add(new LanguageFormatCommand("Unordered List","* "));
FormattingCommands.Add(new LanguageFormatCommand("Ordered List","1. "));
FormattingCommands.Add(new LanguageFormatCommand("Block Quote","> "));
FormattingCommands.Add (new LanguageFormatCommand ());

var Headings = new LanguageFormatCommand ("Headings");
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 1","# "));
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 2","## "));
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 3","### "));
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 4","#### "));
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 5","##### "));
Headings.SubCommands.Add(new LanguageFormatCommand("Heading 6","###### "));
FormattingCommands.Add (Headings);

FormattingCommands.Add(new LanguageFormatCommand ());
FormattingCommands.Add(new LanguageFormatCommand("Link","[","]()"));
FormattingCommands.Add(new LanguageFormatCommand("Image","![](",")"));
FormattingCommands.Add(new LanguageFormatCommand("Image Link","[![](",")](LinkImageHere)"));

Et cette collection passée à la AssembleMenu fonction (avec le menu Format défini comme base), les menus dynamiques et les éléments de menu suivants sont créés :

Nouveaux éléments de menu dans l’application en cours d’exécution

Suppression de menus et d’éléments

Si vous devez supprimer un menu ou un élément de menu de l’interface utilisateur de l’application, vous pouvez utiliser simplement la RemoveItemAt méthode de la NSMenu classe en lui donnant l’index de base zéro de l’élément à supprimer.

Par exemple, pour supprimer les menus et les éléments de menu créés par la routine ci-dessus, vous pouvez utiliser le code suivant :

public void UnpopulateFormattingMenu(NSMenu menu) {

    // Remove any additional items
    for (int n = (int)menu.Count - 1; n > 4; --n) {
        menu.RemoveItemAt (n);
    }
}

Dans le cas du code ci-dessus, les quatre premiers éléments de menu sont créés dans le Générateur d’interface de Xcode et absents disponibles dans l’application, de sorte qu’ils ne sont pas supprimés dynamiquement.

Menus contextuels

Les menus contextuels s’affichent lorsque l’utilisateur clique avec le bouton droit ou clique sur un élément dans une fenêtre. Par défaut, plusieurs éléments de l’interface utilisateur intégrés à macOS ont déjà des menus contextuels qui leur sont attachés (par exemple, l’affichage texte). Toutefois, il peut arriver que nous souhaitions créer nos propres menus contextuels personnalisés pour un élément d’interface utilisateur que nous avons ajouté à une fenêtre.

Nous allons modifier notre fichier Main.storyboard dans Xcode et ajouter une fenêtre Fenêtre à notre conception, définir sa classe sur « NSPanel » dans l’inspecteur d’identité, ajouter un nouvel élément Assistant au menu Fenêtre et l’attacher à la nouvelle fenêtre à l’aide d’un Show Segue :

Définition du type segue dans le fichier storyboard principal.

Procédons comme suit :

  1. Faites glisser une étiquette de l’inspecteur de bibliothèque vers la fenêtre panneau et définissez son texte sur « Propriété » :

    Modification de la valeur de l’étiquette

  2. Ensuite, faites glisser un menu de l’inspecteur de bibliothèque sur le contrôleur de vue dans la hiérarchie d’affichage et renommez les trois éléments de menu par défaut Document, Texte et Police :

    Éléments de menu requis

  3. Maintenant, faites glisser le contrôle à partir de l’étiquette de propriété dans le menu :

    Faire glisser pour créer un segue

  4. Dans la boîte de dialogue contextuelle, sélectionnez Menu :

    Définition du type segue en sélectionnant le menu Des points de vente dans le menu contextuel Étiquette.

  5. À partir de l’inspecteur d’identité, définissez la classe du contrôleur d’affichage sur « PanelViewController » :

    Définition de la classe segue

  6. Revenez à Visual Studio pour Mac pour synchroniser, puis revenez au Générateur d’interface.

  7. Basculez vers l’Éditeur Assistant et sélectionnez le fichier PanelViewController.h.

  8. Créez une action pour l’élément de menu Document appelé propertyDocument:

    Configuration de l’action nommée propertyDocument.

  9. Répétez la création d’actions pour les éléments de menu restants :

    Répétition d’actions pour les éléments de menu restants.

  10. Enfin, créez un point de sortie pour l’étiquette de propriété appelée propertyLabel:

    Configuration de la sortie

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

Modifiez le fichier PanelViewController.cs et ajoutez le code suivant :

partial void propertyDocument (Foundation.NSObject sender) {
    propertyLabel.StringValue = "Document";
}

partial void propertyFont (Foundation.NSObject sender) {
    propertyLabel.StringValue = "Font";
}

partial void propertyText (Foundation.NSObject sender) {
    propertyLabel.StringValue = "Text";
}

Maintenant, si nous exécutons l’application et cliquez avec le bouton droit sur l’étiquette de propriété dans le panneau, nous verrons notre menu contextuel personnalisé. Si nous sélectionnons et élément dans le menu, la valeur de l’étiquette change :

Menu contextuel en cours d’exécution

Examinons ensuite la création de menus de barre d’état.

Menus de la barre d’état

Les menus de barre d’état affichent une collection d’éléments de menu d’état qui fournissent une interaction avec ou des commentaires à l’utilisateur, tels qu’un menu ou une image reflétant l’état d’une application. Le menu de la barre d’état d’une application est activé et actif même si l’application s’exécute en arrière-plan. La barre d’état à l’échelle du système réside à droite de la barre de menus de l’application et est la seule barre d’état actuellement disponible dans macOS.

Nous allons modifier notre fichier AppDelegate.cs et faire en sorte que la DidFinishLaunching méthode ressemble à ce qui suit :

public override void DidFinishLaunching (NSNotification notification)
{
    // Create a status bar menu
    NSStatusBar statusBar = NSStatusBar.SystemStatusBar;

    var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable);
    item.Title = "Text";
    item.HighlightMode = true;
    item.Menu = new NSMenu ("Text");

    var address = new NSMenuItem ("Address");
    address.Activated += (sender, e) => {
        PhraseAddress(address);
    };
    item.Menu.AddItem (address);

    var date = new NSMenuItem ("Date");
    date.Activated += (sender, e) => {
        PhraseDate(date);
    };
    item.Menu.AddItem (date);

    var greeting = new NSMenuItem ("Greeting");
    greeting.Activated += (sender, e) => {
        PhraseGreeting(greeting);
    };
    item.Menu.AddItem (greeting);

    var signature = new NSMenuItem ("Signature");
    signature.Activated += (sender, e) => {
        PhraseSignature(signature);
    };
    item.Menu.AddItem (signature);
}

NSStatusBar statusBar = NSStatusBar.SystemStatusBar; nous donne accès à la barre d’état à l’échelle du système. var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable); crée un élément de barre d’état. À partir de là, nous créons un menu et un certain nombre d’éléments de menu et joignons le menu à l’élément de barre d’état que nous venons de créer.

Si nous exécutons l’application, le nouvel élément de barre d’état s’affiche. La sélection d’un élément dans le menu modifie le texte dans l’affichage texte :

Menu de la barre d’état en cours d’exécution

Ensuite, examinons la création d’éléments de menu d’ancrage personnalisés.

Menus d’ancrage personnalisés

Le menu d’ancrage s’affiche pour votre application Mac lorsque l’utilisateur clique avec le bouton droit ou contrôle sur l’icône de l’application dans le dock :

Menu d’ancrage personnalisé

Nous allons créer un menu d’ancrage personnalisé pour notre application en procédant comme suit :

  1. Dans Visual Studio pour Mac, cliquez avec le bouton droit sur le projet de l’application, puis sélectionnez Ajouter>un nouveau fichier... Dans la boîte de dialogue nouveau fichier, sélectionnez Xamarin.Mac>Empty Interface Definition, utilisez « DockMenu » pour le nom, puis cliquez sur le bouton Nouveau pour créer le fichier DockMenu.xib :

    Ajout d’une définition d’interface vide

  2. Dans le Panneau Solution, double-cliquez sur le fichier DockMenu.xib pour l’ouvrir pour modification dans Xcode. Créez un menu avec les éléments suivants : Adresse, Date, Message d’accueil et Signature

    Disposition de l’interface utilisateur

  3. Ensuite, connectons nos nouveaux éléments de menu à nos actions existantes que nous avons créées pour notre menu personnalisé dans la section Ajout, Modification et Suppression de menus ci-dessus. Basculez vers l’inspecteur d’Connecter ion et sélectionnez le premier répondeur dans la hiérarchie d’interface. Faites défiler vers le bas et recherchez l’action phraseAddress: . Faites glisser une ligne du cercle sur cette action vers l’élément de menu Adresse :

    Faire glisser une ligne vers l’élément de menu Adresse.

  4. Répétez pour tous les autres éléments de menu qui les attachent à leurs actions correspondantes :

    Répétez pour les autres éléments de menu qui les attachent à leurs actions correspondantes.

  5. Ensuite, sélectionnez l’application dans la hiérarchie d’interface. Dans l’inspecteur de Connecter ion, faites glisser une ligne du cercle sur la sortie vers le dockMenu menu que nous venons de créer :

    Faire glisser le câble vers le haut de la sortie

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

  7. Double-cliquez sur le fichier Info.plist pour l’ouvrir pour modification :

    Modification du fichier Info.plist

  8. Cliquez sur l’onglet Source en bas de l’écran :

    Sélection de la vue Source

  9. Cliquez sur Ajouter une nouvelle entrée, cliquez sur le bouton plus vert, définissez le nom de la propriété sur « AppleDockMenu » et la valeur sur « DockMenu » (nom de notre nouveau fichier .xib sans l’extension) :

    Ajout de l’élément DockMenu

Maintenant, si nous exécutons notre application et cliquez avec le bouton droit sur son icône dans le Dock, nos nouveaux éléments de menu seront affichés :

Exemple de menu d’ancrage en cours d’exécution

Si nous sélectionnons l’un des éléments personnalisés dans le menu, le texte de notre affichage texte sera modifié.

Bouton contextuel et listes déroulantes

Un bouton contextuel affiche un élément sélectionné et présente une liste d’options à sélectionner lorsque l’utilisateur clique dessus. Une liste déroulante est un type de bouton contextuel généralement utilisé pour sélectionner des commandes spécifiques au contexte de la tâche actuelle. Les deux peuvent apparaître n’importe où dans une fenêtre.

Nous allons créer un bouton contextuel personnalisé pour notre application en procédant comme suit :

  1. Modifiez le fichier Main.storyboard dans Xcode et faites glisser un bouton contextuel à partir de l’inspecteur de bibliothèque dans la fenêtre Panneau que nous avons créée dans la section Menus contextuels :

    Ajout d’un bouton contextuel

  2. Ajoutez un nouvel élément de menu et définissez les titres des éléments dans la fenêtre contextuelle sur : Adresse, Date, Message d’accueil et Signature

    Configuration des éléments de menu

  3. Ensuite, connectons nos nouveaux éléments de menu aux actions existantes que nous avons créées pour notre menu personnalisé dans la section Ajout, Modification et Suppression de menus ci-dessus. Basculez vers l’inspecteur d’Connecter ion et sélectionnez le premier répondeur dans la hiérarchie d’interface. Faites défiler vers le bas et recherchez l’action phraseAddress: . Faites glisser une ligne du cercle sur cette action vers l’élément de menu Adresse :

    Faire glisser vers le haut une action

  4. Répétez pour tous les autres éléments de menu qui les attachent à leurs actions correspondantes :

    Toutes les actions requises

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

Maintenant, si nous exécutons notre application et que nous sélectionnons un élément dans la fenêtre contextuelle, le texte de notre affichage texte change :

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

Vous pouvez créer et utiliser des listes déroulantes de la même façon que les boutons contextuels. Au lieu de vous attacher à une action existante, vous pouvez créer vos propres actions personnalisées comme nous l’avons fait pour notre menu contextuel dans la section Menus contextuels .

Résumé

Cet article a examiné en détail l’utilisation des menus et des éléments de menu dans une application Xamarin.Mac. Tout d’abord, nous avons examiné la barre de menus de l’application, puis nous avons examiné la création de menus contextuels, puis nous avons examiné les menus de barre d’état et les menus d’ancrage personnalisés. Enfin, nous avons couvert les menus contextuels et les listes déroulantes.