Menus Using menus in a Xamarin.Mac application Contents This article will cover the following topics in detail: The Application's Menu Bar The Default Application Menu Bar Built-In Menu Functionality Enabling and Disabling Menus and Items Enabling and Responding to Menu Items in Code Adding, Editing and Deleting Menus Contextual Menus Status Bar Menus Custom Dock Menus Pop-up Button and Pull-Down Lists Overview When working with C# and .NET in a Xamarin.Mac application, you have access to the same Cocoa Menus that a developer working in in Objective-C and Xcode does. Because Xamarin.Mac integrates directly with Xcode, you can use Xcode's Interface Builder to create and maintain your Menu Bars, Menus and Menu Items (or optionally create them directly in C# code). Menus are a integral part of a Mac application's user experience and commonly appear in various parts of the user interface: The Application's Menu Bar - This is the main menu that appears at the top of the screen for every Mac Application. Contextual Menus - These appear when the user right-clicks or left-control-clicks an item in a window. The Status Bar - This is the area at the far right side of the Application Menu Bar that appears at the top of the screen (to the left of the menu bar clock) and grows to the left as items are added to it. Dock Menu - The menu for each application in the dock that appears when the user right-clicks or leftcontrol-clicks the application's icon, or when the user left-clicks the icon and holds the mouse button down. Pop-up Button and Pull-Down Lists - A Pop-up Button displays a selected item and presents a list of options to select from when clicked by the user. A Pull-Down list is a type of Pop-up Button usually used for selecting commands specific to the context of the current task. Both can appear anywhere in a window. In this article, we'll cover the basics of working with Cocoa Menu Bars, Menus and Menu Items in a Xamarin.Mac application. It is highly suggested that you work through the Hello, Mac article first, specifically the Introduction to Xcode and Interface Builder and Outlets and Actions sections, as it covers key concepts and techniques that we'll be using in this article. You may want to take a look at the Exposing C# classes / methods to Objective-C section of the Xamarin.Mac Internals document as well, it explains the Register and Export commands used to wire-up your C# classes to Objective-C objects and UI Elements. The Application's Menu Bar Unlike applications running on the Windows OS where every window can have it's own menu bar attached to it, every application running on Mac OS X has a single Menu Bar that runs along the top of the screen that's used for every window in that application: Items on this Menu Bar are activated or deactivated based on the current context or state of the application and it's user interface at any given moment. For example: if the user selects a text field, items on the Edit menu will be come enabled such as Copy and Cut. According to Apple and by default, all Mac OS X application's have a standard set of Menus and Menu Items that appear in the Application's Menu Bar: The Apple Menu - This menu provides access to system wide items that are available to the user at all times, regardless of what application is running. These items cannot be modified by the developer. The App Menu - This menu displays the application's name in bold and helps the user identify what application is currently running. It contains items that apply to the application as a whole and not a given document or process such as quitting the application. The File Menu - Items used to create, open or save documents that your application works with. If your application is not document based, this menu can be renamed or removed. The Edit Menu - Holds command such as Cut, Copy and Paste and are used to edit or modify elements in the applications user interface. The Format Menu - If the application works with text, this menu holds commands to adjust the formatting of that text. The View Menu - Holds command that affect how content is displayed (viewed) in the application's user interface. Application Specific Menus - These are any menus that are specific to your applications (such as Bookmarks for a web browser). They should appear between the View and Windows menus on the bar. The Windows Menu - Contains commands for working with windows in your application, as well as a list of current open windows. The Help Menu - If your application provides onscreen help, the Help menu should be the right-most menu on the bar. For more information about the Application Menu Bar and standard Menus and Menu Items, please see Apple's Menu Bar Menus section of the OS X Human Interface Guidelines. The Default Application Menu Bar Whenever you create a new Xamarin.Mac project, you automatically get a standard, default Application Menu Bar that has the typical items that a Mac OS X application would normally have (as discussed in the section above). Your application's default Menu Bar is defined in the ManiMenu.xib file under the Project in the Solution Explorer: Double-click the ManiMenu.xib file to open it for editing in Xcode's Interface Builder and you'll be presented with the Menu Editor Interface: From here we can click on items such as the Open menu item in the File menu and edit or adjust it's properties in the Attributes Inspector: We'll get into adding, editing and deleting Menus and Items later in this article. For now we just want to see what Menus and Menu Items are available by default and how they have been automatically exposed to code via a set of predefined Outlets and Actions (for more information see our Outlets and Actions documentation). For example, if we click on the Connection Inspector for the Open menu item we can see it is automatically wired-up the openDocument: Action: If you select the First Responder in the Interface Hierarchy and scroll down in the Connection Inspector, and you will see the definition of the openDocument: Action that the Open menu item is attached to (along with several other default Actions for the application that are and are not automatically wired-up to controls): Why is this important? In the next section will see how these automatically defined Actions work with other Cocoa user interface elements to automatically enable and disable menu items, as well as, provide built-in functionality for the items. Later we'll be using these built-in Actions to enable and disable items from code and provide our own functionality when they are selected. Built-In Menu Functionality If you were the run a newly created Xamarin.Mac application before adding any UI items or code, you'll notice that some items are automatically wired-up and enabled for you (with fully functionality automatically built-in), such as the Quit item in the App Menu: While other Menu Items, such as Cut, Copy and Paste are not: Let's stop the application and double-click the MainWindow.xib file in the Solution Explorer to open it for editing in Xcode's Interface Builder. Next, drag a Text View from the Library onto the Window in the Interface Editor: In the Positioning Inspector let's pin the Text View to the Window's edges and set it where it grows and shrinks with the window: Save your changes to the user interface design and switch back the Xamarin Studio to synchronize the changes with your Xamarin.Mac project. Now start the application, type some text into the text view, select it and open the Edit menu: Notice how the Cut, Copy and Paste are automatically enabled and fully functional, all without writing a single line of code. What's going on here? Remember the built-in predefine Actions that come wired-up to the default Menu Items (as presented above), most of the Cocoa User Interface elements that are part of OS X have built in hooks to specific Actions (such as copy:). So when they are added to a window, active and selected, the corresponding Menu Item or Items attached to that Action are automatically enable. If the user selects that Menu Item, the functionality built into the UI element is called and executed, all without developer intervention. Enabling and Disabling Menus and Items By default, every time a user event occurs, NSMenu automatically enables and disables each visible Menu and Menu Item based on the context of the application. There are two ways to enable/disable an item: Automatic Menu Enabling - A Menu Item is enabled if NSMenu can find an appropriate object that responds to the Action that the item is wired-up to. For example, the Text View above that had a built in hook to the copy: Action. Manual Menu Enabling - You manually set the Enabled property of each NSMenuItem to enable or disable each item in a menu individually. To choose a system, set the AutoEnablesItems property of a NSMenu where true is automatic (the default behavior) and false is manual. Note: If you choose to use Manual Menu Enabling, none of the menu items, even those controlled by Application Kit classes like NSTextView, are updated automatically. You will be responsible for enabling and disabling all items by hand in code. Enabling and Responding to Menu Items in Code As we have seen above, just by adding specific Cocoa User Interface elements to our UI design (such as a Text Field), several of the default Menu Items will be enabled and function automatically, without having to write any code. Next let's look at adding our own C# code to our Xamarin.Mac project to enable a Menu Item and provide functionality when the user selects it. For example, let say we want the user to be able to use the Open item in the File menu to select a folder. Since we want this to be an application wide function and not limited to a give window or UI element, we're going to add the code to handle this to our Application Delegate. In the Solution Explorer, double-click the AppDelegate.CS file to open it for editing: Add the following code below the DidFinishLaunching method: [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 (); } } Let's run the application now and open the File menu: Notice that the Open menu item is now enabled. If we select it, the Open Dialog Box will be displayed: If we click the Open button, our alert message will be displayed: The key line here was [Export ("openDocument:")], it tells NSMenu that our AppDelegate has a method void OpenDialog (NSObject sender) that responds to the openDocument: Action. If you'll remember above, the Open menu item is automatically wired-up to this Action by default in Interface Builder: Next let's look at creating our own Menu, Menu Items and Actions and responding to them in code. Adding, Editing and Deleting Menus As we have seen in the previous sections, a Xamarin.Mac application comes with a preset number of standard, default Menus and Menus Items that specific UI controls will automatically activate and respond to. We have also seen how to add code to our application that will also enable and respond to these default items. In this section we will look at removing menu items that we don't need, reorganizing menus and adding new Menus, Menu Items and Actions. Double-click the MainMenu.xib file in the Solution Explorer to open it for editing: For our specific Xamarin.Mac application we are not going to be using the default View menu so we are going to remove it. In the Interface Hierarchy select the View menu item that is a part of the main menu bar: Press the Delete or Backspace key to delete the menu. Next, we aren't going to be using all of the items in the Format menu and we want to move the items we are going to use out from under the sub menus. In the Interface Hierarchy select the following menu items: Drag the items under the parent Menu from the sub menu where they currently are: Your Menu should now look like: Next let's drag the Text sub menu out from under the Format menu and place it on the Main Menubar between the Format and Window menus: Let's go back under the Format menu and delete the Font sub menu item. Next, select the Format Menu and rename it Font: Next, let's create a custom menu of predefine phrases that will automatically get appended to the text in the Text View when they are selected. In the search box at the bottom on the Library Inspector type in menu, this will make it easier to find and work with all of the menu UI elements: Now let's do the following to create our menu: 1. Drag a Menu Item from the Library Inspector onto the Menubar between the Text and Window menus: 2. Rename the item Phrases: 3. Next drag a Menu from the Library Inspector: 4. Drop then Menu on the new Menu Item we just created and change it's name to Phrases: 5. Now let's rename the three default Menu Items Address, Date and Greeting: 6. Let's add a fourth Menu Item by dragging a Menu Item from the Library Inspector and calling it Signature: 7. Save the changes to the Menubar. Now let's create a set of custom Actions so that our new Menu Items are exposed to C# code. In Xcode let's switch to the Assistant view: Let's do the following: 1. Control-drag from the Address Menu Item to the AppDelegate.h file: 2. Switch the Connection type to Action: 3. Enter a Name of phraseAddress and press the Connect button to create the new Action: 4. Repeat the above steps for the Date, Greeting and Signature Menu Items: 5. Save the changes to the Menubar. Next we need to create an Outlet for our Text View so that we can adjust it's content from code. Switch to the MainWindow.xib file, select the MainWindow.h file in the Assistant Editor and create a new Outlet called documentText: Return to Xamarin Studio to sync the changes from Xcode. Next edit the MainWindow.cs file and add the following computed property: public string Text { get { return documentText.Value; } set { documentText.Value = value; } } This exposes the text of our Text View outside of the MainWindow class. Now edit the AppDelegate.cs file and add the following computed property: public MainWindow textEditor { get; set;} Edit the DidFinishLaunching method and make it look like the following: public override void DidFinishLaunching (NSNotification notification) { mainWindowController = new MainWindowController (); mainWindowController.Window.MakeKeyAndOrderFront (this); // Save access to the main window textEditor = mainWindowController.Window; } Now add the following methods to handle our new, custom Menu and Menu Items: [Export ("phraseAddress:")] void PhraseAddress (NSObject sender) { textEditor.Text += "Xamarin HQ\n394 Pacific Ave, 4th Floor\nSan Francisco CA 94111\n\n"; } [Export ("phraseDate:")] void PhraseDate (NSObject sender) { textEditor.Text += DateTime.Now.ToString("D"); } [Export ("phraseGreeting:")] void PhraseGreeting (NSObject sender) { textEditor.Text += "Dear Sirs,\n\n"; } [Export ("phraseSignature:")] void PhraseSignature (NSObject sender) { textEditor.Text += "Sincerely,\n\nKevin Mullins\nXamarin,Inc.\n"; } Now if we run our application, all of the items in the Phrase menu will be active and will add the give phrase to the Text View when selected: Now that we have the basics of working with the Application Menu Bar down, let's look at creating a custom Contextual Menu. Contextual Menus Contextual Menus appear when the user right-clicks or left-Control-clicks an item in a window. By default, several of the UI elements built into OS X already have contextual menus attached to them (such as the Text View). However, there might be times when we want to create our own custom Contextual Menus for a UI element that we have added to a window. Let's edit our MainWindow.xib file in Xcode and add a Panel window to our design: Let's do the following: 1. Drag a Label from the Library Inspector onto the Panel window and set its text to Property: 2. Next drag a Menu from the Library Inspector into the design and rename the three default menu items Document, Text and Font: 3. Now control-drag from the Property Label onto the Menu: 4. From the popup dialog, select Menu: 5. Switch to the Assistant Editor and select the MainWindow.h file. 6. Create an Action for the Document menu item called propertyDocument: 7. Repeat creating Actions for the remaining menu items: 8. Finally create an Outlet for the Property Label called propertyLabel: 9. Save your changes and return to Xamarin Studio to sync with Xcode. Edit the MainWindow.cs file and add the following code: [Export ("propertyDocument:")] void PropertyDocument (NSObject sender) { propertyLabel.StringValue = "Document"; } [Export ("propertyFont:")] void PropertyFont (NSObject sender) { propertyLabel.StringValue = "Font"; } [Export ("propertyText:")] void PropertyText (NSObject sender) { propertyLabel.StringValue = "Text"; } Now if we run the application and right-click on the Property label in the Panel, we'll see our custom Contextual Menu. If we select and item from the menu, the label's value will change: Next let's look at creating Status Bar Menus. Status Bar Menus Status Bar Menus display a collection of status menu items that provide interaction with or feedback to the user, such as a menu or an image reflecting an application’s state. An application's Status Bar Menu is enabled and active even if the application is running in the background. The system-wide Status Bar resides at the right side of the Application Menu Bar and is the only Status Bar currently available in Mac OS X. Let's edit our AppDelegate.cs file and make the DidFinishLaunching method look like the following: public override void DidFinishLaunching (NSNotification notification) { mainWindowController = new MainWindowController (); mainWindowController.Window.MakeKeyAndOrderFront (this); // Save access to the main window textEditor = mainWindowController.Window; // 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); } The NSStatusBar statusBar = NSStatusBar.SystemStatusBar; gives us access to the system-wide status bar. The var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable); creates a new Status Bar Item. From there we create a Menu and a number of Menu Items and attach the menu to the Status Bar Item we just created. If we run the application, the new Status Bar Item will be displayed. Selecting an item from the menu will change the text in the Text View: Next, let's look at creating custom Dock Menu Items. Custom Dock Menus The Dock Menu appears for you Mac application when the user right-clicks or control-left-clicks the application's icon in the Dock: Let's create a custom Dock Menu for our application by doing the following: 1. In Xamarin Studio, right-click on the application's project and select Add > New File... From the New File dialog box, select Xamarin.Mac > Empty Interface Definition, use DockMenu for the Name and click the New button to create the new DockMenu.xib file: 2. In the Solution Explorer, double-click the DockMenu.xib file to open it for editing in Xcode. Create a new Menu with the following items: Address, Date, Greeting and Signature 3. Next, let's connect our new menu items to our existing Actions that we created for our custom menu in the Adding, Editing and Deleting Menus section above. Switch to the Connection Inspector and select the First Responder in the Interface Hierarchy. Scroll down and find the phraseAddress: Action. Drag a line from the circle on that Action to the Address Menu Item: 4. Repeat for all of the other Menu Items attaching them to their corresponding Actions: 5. Next, select the Application in the Interface Hierarchy. In the Connection Inspector, drag a line from the circle on the dockMenu Outlet to the Menu we just created: 6. Save your changes and switch back to Xamarin Studio to sync with Xcode. 7. Double-click the Info.plist file to open it for editing: 8. Click the Source tab at the bottom of the screen: 9. Click Add new entry, click the Green Plus, set the property name as AppleDockMenu and the value of DockMenu (the name of our new .xib file without the extension): Now if we run our application and right-click on it's icon in the Dock, our new menu items will be displayed: If we select one of the custom items from the menu, the text in our Text View will be modified. Pop-up Button and Pull-Down Lists A Pop-up Button displays a selected item and presents a list of options to select from when clicked by the user. A Pull-Down list is a type of Pop-up Button usually used for selecting commands specific to the context of the current task. Both can appear anywhere in a window. Let's create a custom Pop-up Button for our application by doing the following: 1. Edit the MainWindow.xib file in Xcode and drag a Popup Button from the Library Inspector onto the Panel window we created in the Contextual Menus section: 2. Add a new Menu Item and set the titles of the Items in the Popup to: Address, Date, Greeting and Signature 3. Next, let's connect our new menu items to our existing Actions that we created for our custom menu in the Adding, Editing and Deleting Menus section above. Switch to the Connection Inspector and select the First Responder in the Interface Hierarchy. Scroll down and find the phraseAddress: Action. Drag a line from the circle on that Action to the Address Menu Item: 4. Repeat for all of the other Menu Items attaching them to their corresponding Actions: 5. Save your changes and switch back to Xamarin Studio to sync with Xcode. Now if we run our application and select an item from the popup, the text in our Text View will change: You can create and work with Pull-Down Lists in the exact same way as Pop-up Buttons. Instead of attaching to existing Actions, you could create your own custom Actions just like we did for our Contextual Menu in the Contextual Menus section. Summary In this article has taken a detailed look at working with Menus and Menu Items in a Xamarin.Mac application. First we examined the Application's Menu Bar, then we looked at creating Contextual Menus, next we examined Status Bar Menus and Custom Dock Menus. Finally, we covered Pop-up Menus and Pull-Down Lists.
© Copyright 2024