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.
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 :
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 :
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 :
À 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 :
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:
:
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) :
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 :
Bien que d’autres éléments de menu, tels que Couper, Copier et Coller , ne soient pas :
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 :
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 :
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 :
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’actioncopy:
. - 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 chaqueNSMenuItem
é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 :
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 NSTextView
code, 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) :
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 :
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 :
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 :
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 :
Si nous cliquez sur le bouton Ouvrir , notre message d’alerte s’affiche :
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 :
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 NSDocuments
pas , vous utilisez toujours le NSDocumentController
menu Ouvrir récent en envoyant un NSUrl
emplacement du fichier à la NoteNewRecentDocumentURL
méthode du SharedDocumentController
fichier .
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 :
Cliquez sur le + bouton en bas de l’inspecteur d’attributs pour ajouter une nouvelle action personnalisée :
Donnez-lui le même nom que l’action personnalisée que vous avez créée sur votre contrôleur de fenêtre :
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) :
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 :
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 :
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 :
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 :
Faites glisser les éléments sous le menu parent à partir du sous-menu où ils sont actuellement :
Votre menu doit maintenant ressembler à ceci :
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 :
Revenons sous le menu Format et supprimez l’élément de sous-menu Police . Ensuite, sélectionnez le menu Format et renommez-le « 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 :
À présent, procédons comme suit pour créer notre menu :
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 :
Renommez l’élément « Phrases » :
Ensuite, faites glisser un menu à partir de l’inspecteur de bibliothèque :
Déposez puis menu dans le nouvel élément de menu que nous venons de créer et remplacez son nom par « Phrases » :
Nous allons maintenant renommer les trois éléments de menu par défaut « Adresse », « Date » et « Salutation » :
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 » :
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 :
Procédons comme suit :
Faites glisser le contrôle de l’élément de menu Adresse vers le fichier AppDelegate.h .
Basculez le type d’Connecter ion en Action :
Entrez un nom de « phraseAddress » et appuyez sur le bouton Connecter pour créer l’action :
Répétez les étapes ci-dessus pour les éléments de menu Date, Salutation et Signature :
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
:
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 :
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 LanguageFormatCommand
nouveaux 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 :
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 :
Procédons comme suit :
Faites glisser une étiquette de l’inspecteur de bibliothèque vers la fenêtre panneau et définissez son texte sur « Propriété » :
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 :
Maintenant, faites glisser le contrôle à partir de l’étiquette de propriété dans le menu :
Dans la boîte de dialogue contextuelle, sélectionnez Menu :
À partir de l’inspecteur d’identité, définissez la classe du contrôleur d’affichage sur « PanelViewController » :
Revenez à Visual Studio pour Mac pour synchroniser, puis revenez au Générateur d’interface.
Basculez vers l’Éditeur Assistant et sélectionnez le fichier PanelViewController.h.
Créez une action pour l’élément de menu Document appelé
propertyDocument
:Répétez la création d’actions pour les éléments de menu restants :
Enfin, créez un point de sortie pour l’étiquette de propriété appelée
propertyLabel
: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 :
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 :
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 :
Nous allons créer un menu d’ancrage personnalisé pour notre application en procédant comme suit :
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 :
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
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 :Répétez pour tous les autres éléments de menu qui les attachent à leurs actions correspondantes :
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 :Enregistrez vos modifications et revenez à Visual Studio pour Mac pour vous synchroniser avec Xcode.
Double-cliquez sur le fichier Info.plist pour l’ouvrir pour modification :
Cliquez sur l’onglet Source en bas de l’écran :
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) :
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 :
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 :
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 :
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
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 :Répétez pour tous les autres éléments de menu qui les attachent à leurs actions correspondantes :
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 :
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.