Меню в Xamarin. MacMenus in Xamarin.Mac

В этой статье рассматривается работа с меню в приложении Xamarin. Mac. Здесь описывается создание и обслуживание меню и пунктов меню в Xcode и Interface Builder и работа с ними программными средствами.This article covers working with menus in a Xamarin.Mac application. It describes creating and maintaining menus and menu items in Xcode and Interface Builder and working with them programmatically.

При работе с C# и .NET в приложении Xamarin. Mac у вас есть доступ к тем же меню Cocoa, что и разработчик, работающий на уровне цели-C и Xcode.When working with C# and .NET in a Xamarin.Mac application, you have access to the same Cocoa menus that a developer working in Objective-C and Xcode does. Поскольку Xamarin. Mac интегрируется непосредственно с Xcode, можно использовать Interface Builder Xcode для создания и обслуживания строк меню, меню и пунктов меню (или при необходимости создавать их непосредственно в C# коде).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).

Меню являются неотъемлемой частью пользовательского интерфейса приложения Mac и обычно отображаются в различных частях интерфейсного пользователя:Menus are an integral part of a Mac application's user experience and commonly appear in various parts of the user interface:

  • Строка меню приложения — это главное меню, которое отображается в верхней части экрана для каждого приложения Mac.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 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 control-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.

Пример менюAn example menu

В этой статье рассматриваются основы работы с Cocoa меню, меню и элементами меню в приложении Xamarin. Mac.In this article, we'll cover the basics of working with Cocoa menu bars, menus, and menu items in a Xamarin.Mac application. Мы настоятельно рекомендуем сначала ознакомиться со статьей Hello, Mac , в частности Знакомство с Xcode и Interface Builder , а также с разделом "возможности и действия ", так как в нем рассматриваются основные понятия и методы, которые мы будем использовать в Эта статья.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.

Возможно, вы захотите ознакомиться с разделом C# классы и методы для цели-C в документе о внутренних компонентах Xamarin. Mac , а также объясняются атрибуты и Register Export , используемые для подключения C# классов к Объекты цели-C и элементы пользовательского интерфейса.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 attributes used to wire-up your C# classes to Objective-C objects and UI elements.

Строка меню приложенияThe application's menu bar

В отличие от приложений, работающих в ОС Windows, где каждое окно может иметь собственную строку меню, каждое приложение, работающее в macOS, имеет одну строку меню, которая работает в верхней части экрана, используемой для каждого окна в этом приложении:Unlike applications running on the Windows OS where every window can have its own menu bar attached to it, every application running on macOS has a single menu bar that runs along the top of the screen that's used for every window in that application:

Строка менюA menu bar

Элементы в этой строке меню активируются или деактивируются на основе текущего контекста или состояния приложения и его пользовательского интерфейса в любой момент.Items on this menu bar are activated or deactivated based on the current context or state of the application and its 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.

В соответствии с Apple и по умолчанию все приложения macOS имеют стандартный набор меню и пунктов меню, которые отображаются в строке меню приложения:According to Apple and by default, all macOS applications have a standard set of menus and menu items that appear in the application's menu bar:

  • Меню Apple . Это меню предоставляет доступ к элементам всей системы, доступным для пользователя, независимо от того, какое приложение выполняется.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.
  • Меню "приложение " — это меню отображает имя приложения полужирным шрифтом и помогает пользователю определить, какое приложение выполняется в данный момент.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.
  • Меню "файл " — элементы, используемые для создания, открытия и сохранения документов, с которыми работает приложение.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.
  • Меню «Правка » — содержит такие команды, как вырезание, копированиеи Вставка , которые используются для изменения или изменения элементов пользовательского интерфейса приложения.Edit menu - Holds commands such as Cut, Copy, and Paste which are used to edit or modify elements in the application's user interface.
  • Меню "формат " — Если приложение работает с текстом, в этом меню содержатся команды для настройки форматирования этого текста.Format menu - If the application works with text, this menu holds commands to adjust the formatting of that text.
  • Меню "вид " — содержит команды, влияющие на отображение (Просмотр) содержимого в пользовательском интерфейсе приложения.View menu - Holds commands 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 application (such as a bookmarks menu for a web browser). Они должны отображаться между меню вид и окно на панели.They should appear between the View and Window menus on the bar.
  • Меню "окно " — содержит команды для работы с окнами в приложении, а также список текущих открытых окон.Window menu - Contains commands for working with windows in your application, as well as a list of current open windows.
  • Меню "Справка ". Если приложение предоставляет справку на экране, меню "Справка" должно быть самым подменю на панели.Help menu - If your application provides onscreen help, the Help menu should be the right-most menu on the bar.

Дополнительные сведения о строке меню приложения и стандартных меню и пунктах меню см. в разделе рекомендации по использованию человеческого интерфейсаApple.For more information about the application menu bar and standard menus and menu items, please see Apple's Human Interface Guidelines.

Строка меню приложения по умолчаниюThe default application menu bar

При создании нового проекта Xamarin. Mac вы автоматически получаете стандартную строку меню приложения по умолчанию с типичными элементами, которые обычно macOS в приложении (как описано в разделе выше).Whenever you create a new Xamarin.Mac project, you automatically get a standard, default application menu bar that has the typical items that a macOS application would normally have (as discussed in the section above). Строка меню по умолчанию приложения определена в файле Main. Storyboard (вместе с остальной частью пользовательского интерфейса приложения) в проекте на панель решения:Your application's default menu bar is defined in the Main.storyboard file (along with the rest of your app's UI) under the project in the Solution Pad:

![Выбор основной] раскадровки (menu-images/appmenu02.png "Выбор основной") раскадровкиSelect the main storyboard

Дважды щелкните файл Main. Storyboard , чтобы открыть его для редактирования в Interface Builder Xcode и вы увидите интерфейс редактора меню:Double-click the Main.storyboard file to open it for editing in Xcode's Interface Builder and you'll be presented with the menu editor interface:

Изменение пользовательского интерфейса в XcodeEditing the UI in Xcode

Здесь можно щелкнуть элемент меню Открыть в меню файл и изменить или изменить его свойства в инспекторе атрибутов:From here we can click on items such as the Open menu item in the File menu and edit or adjust its properties in the Attributes Inspector:

Изменение атрибутов менюEditing a menu's attributes

Далее в этой статье мы будем добавлять, изменять и удалять меню и элементы.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).

Например, если щелкнуть инспектор подключений для пункта меню Открыть , он будет автоматически привязан к openDocument: действию:For example, if we click on the Connection Inspector for the Open menu item we can see it is automatically wired up to the openDocument: action:

Просмотр присоединенного действияViewing the attached action

Если выбрать первый ответчик в иерархии интерфейсов и прокрутить вниз в инспекторе подключений, вы openDocument: увидите определение действия, к которому присоединен пункт меню Открыть (вместе с несколькими другие действия по умолчанию для приложения, которые не привязаны к элементам управления автоматически.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):

Просмотр всех вложенных действийViewing all attached actions

Почему это важно?Why is this important? В следующем разделе будет показано, как эти автоматически определенные действия работают с другими элементами пользовательского интерфейса Cocoa, чтобы автоматически включать и отключать пункты меню, а также предоставлять встроенные функции для элементов.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

Если вы выполняли только что созданное приложение Xamarin. Mac перед добавлением элементов пользовательского интерфейса или кода, вы заметите, что некоторые элементы автоматически подсоединены и включены (с автоматически встроенными функциями), например " Quit " в элементе Меню приложения :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:

Включенный пункт менюAn enabled menu item

Хотя другие пункты меню, такие как вырезание, копированиеи Вставка , не выполняются:While other menu items, such as Cut, Copy, and Paste are not:

Отключенные пункты менюDisabled menu items

Давайте откроем приложение и дважды щелкните файл Main. Storyboard в панель решения , чтобы открыть его для редактирования в Interface Builder Xcode.Let's stop the application and double-click the Main.storyboard file in the Solution Pad to open it for editing in Xcode's Interface Builder. Затем перетащите текстовое представление из библиотеки на контроллер представления окна в редакторе интерфейса:Next, drag a Text View from the Library onto the window's view controller in the Interface Editor:

Выбор текстового представления из библиотекиSelecting a Text View from the Library

В редакторе ограничений Прикрепите текстовое представление к краям окна и задайте его там, где оно растет и сжимается, щелкнув все четыре красной кнопки I-беамс в верхней части редактора и нажав кнопку Добавить 4 ограничения :In the Constraint Editor let's pin the text view to the window's edges and set it where it grows and shrinks with the window by clicking all four red I-beams at the top of the editor and clicking the Add 4 Constraints button:

Изменение очередностьюEditing the contraints

Сохраните изменения в структуре пользовательского интерфейса и переключитесь обратно на Visual Studio для Mac, чтобы синхронизировать изменения с проектом Xamarin. Mac.Save your changes to the user interface design and switch back the Visual Studio for Mac 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:

![Элементы меню автоматически включаются и] отключаются. (menu-images/appmenu07.png "Элементы меню автоматически включаются и") отключаются.The menu items are automatically enabled/disabled

Обратите внимание, что элементы " Вырезать", " Копировать" и " Вставить " автоматически включены и полностью работают, без написания одной строки кода.Notice how the Cut, Copy, and Paste items are automatically enabled and fully functional, all without writing a single line of code.

Что здесь происходит?What's going on here? Помните о встроенных предопределенных действиях, которые связаны с элементами меню по умолчанию (как было показано выше), большинство элементов пользовательского интерфейса Cocoa, которые являются частью macOS, имеют встроенные обработчики для определенных действий (например copy:,).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 macOS 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 enabled. Если пользователь выбирает этот пункт меню, функциональные возможности, встроенные в элемент пользовательского интерфейса, вызываются и выполняются, все без участия разработчика.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

По умолчанию каждый раз, когда происходит событие пользователя NSMenu , автоматически включает и отключает каждое видимое меню и пункт меню на основе контекста приложения.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 three ways to enable/disable an item:

  • Автоматическое включение меню — пункт меню включается, если NSMenu может найти подходящий объект, отвечающий на действие, к которому привязан элемент.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. Например, представленное выше текстовое представление содержит встроенное подключение к copy: действию.For example, the text view above that had a built-in hook to the copy: action.
  • Настраиваемые действия и валидатеменуитем: — для любого элемента меню, привязанного к окну или настраиваемому действию контроллера представлений, validateMenuItem: можно добавить действие и вручную включить или отключить пункты меню.Custom actions and validateMenuItem: - For any menu item that is bound to a window or view controller custom action, you can add the validateMenuItem: action and manually enable or disable menu items.
  • Включение меню вручную . NSMenuItem для включения или отключения Enabled каждого элемента в меню вручную задайте для свойства значение.Manual menu enabling - You manually set the Enabled property of each NSMenuItem to enable or disable each item in a menu individually.

Чтобы выбрать систему, задайте AutoEnablesItems свойство NSMenuобъекта.To choose a system, set the AutoEnablesItems property of a NSMenu. trueявляется автоматическим (поведение по умолчанию false ) и выполняется вручную.true is automatic (the default behavior) and false is manual.

Важно!

Если вы решили использовать ручное меню, ни один из пунктов меню, даже не управляемые классами AppKit, как NSTextView, обновляются автоматически.If you choose to use manual menu enabling, none of the menu items, even those controlled by AppKit classes like NSTextView, are updated automatically. Вы несете ответственность за включение и отключение всех элементов вручную в коде.You will be responsible for enabling and disabling all items by hand in code.

Использование ВалидатеменуитемUsing validateMenuItem

Как упоминалось выше, для любого элемента меню, привязанного к настраиваемому действию контроллера окна или представления, можно добавить validateMenuItem: действие и вручную включить или отключить пункты меню.As stated above, for any menu item that is bound to a Window or View Controller Custom Action, you can add the validateMenuItem: action and manually enable or disable menu items.

В следующем примере Tag свойство будет использоваться для выбора типа элемента меню, который будет включен или отключен validateMenuItem: действием в зависимости от состояния выбранного текста в NSTextView.In the following example, the Tag property will be used to decide the type of menu item that will be enabled/disabled by the validateMenuItem: action based on the state of selected text in a NSTextView. Tag Свойство было задано в Interface Builder для каждого пункта меню:The Tag property has been set in Interface Builder for each menu item:

Установка свойства TagSetting the Tag property

И следующий код добавлен в контроллер представления:And the following code added to the View Controller:

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

При выполнении этого кода и отсутствии выделенного текста в NSTextViewдва элемента меню "оболочка" отключаются (даже если они связаны с действиями на контроллере представления):When this code is run, and no text is selected in the NSTextView, the two wrap menu items are disabled (even though they are wired to actions on the view controller):

Отображение отключенных элементовShowing disabled items

Если раздел текста выбран и меню открывается снова, то будут доступны два элемента меню "заключение":If a section of text is selected and the menu reopened, the two wrap menu items will be available:

Отображение включенных элементовShowing enabled items

Включение и реагирование на пункты меню в кодеEnabling and responding to menu items in code

Как мы видели выше, просто добавляя определенные элементы пользовательского интерфейса Cocoa в нашу структуру пользовательского интерфейса (например, текстовое поле), некоторые элементы меню по умолчанию будут включены и работать автоматически, не требуя написания кода.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. Теперь рассмотрим добавление собственного C# кода в проект Xamarin. Mac для включения пункта меню и предоставления функциональных возможностей, когда пользователь выбирает его.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.

В панель решениядважды щелкните AppDelegate.CS файл, чтобы открыть его для редактирования:In the Solution Pad, double-click the AppDelegate.CS file to open it for editing:

Выбор делегата приложенияSelecting the app delegate

Добавьте следующий код под DidFinishLaunching методом: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:

Меню «файл»The File menu

Обратите внимание, что теперь пункт Открыть меню включен.Notice that the Open menu item is now enabled. Если выбрать его, откроется диалоговое окно Открыть:If we select it, the open dialog will be displayed:

Открытое диалоговое окноAn open dialog

Если нажать кнопку " Открыть ", отобразится сообщение с предупреждением:If we click the Open button, our alert message will be displayed:

Пример сообщения диалогового окнаAn example dialog message

Вот [Export ("openDocument:")]ключевая строка, которая говорит NSMenu , что наш AppDelegate имеет метод void OpenDialog (NSObject sender) , отвечающий openDocument: на действие.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. Если вы запомним выше, пункт меню Открыть автоматически поддается этому действию по умолчанию в Interface Builder:If you'll remember from above, the Open menu item is automatically wired-up to this action by default in Interface Builder:

Просмотр вложенных действийViewing the attached actions

Теперь рассмотрим создание собственного меню, пунктов меню и действий и реагирование на них в коде.Next let's look at creating our own menu, menu items, and actions and responding to them in code.

Работа с меню "открыть недавно"Working with the open recent menu

По умолчанию меню файл содержит открытый элемент, который отслеживает последние несколько файлов, открытых пользователем в приложении.By default, the File menu contains an Open Recent item that keeps track of the last several files that the user has opened with your app. При создании NSDocument на основе приложения Xamarin. Mac это меню будет автоматически обработано.If you are creating a NSDocument based Xamarin.Mac app, this menu will be handled for you automatically. Для любого другого типа приложения Xamarin. Mac вы будете отвечать за управление этим элементом меню и реагирование на него вручную.For any other type of Xamarin.Mac app, you will be responsible for managing and responding to this menu item manually.

Чтобы вручную обрабатывали меню Открыть недавно , сначала необходимо сообщить о том, что новый файл открыт или сохранен с помощью следующей команды:To manually handle the Open Recent menu, you will first need to inform it that a new file has been opened or saved using the following:

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

Несмотря на то, что приложение не NSDocumentsиспользуется, вы по- NSDocumentController прежнему используете для поддержания меню Открыть последние , отправляя в NSUrl NoteNewRecentDocumentURL метод компонента SharedDocumentControllerобъект с расположением файла.Even though your app is not using NSDocuments, you still use the NSDocumentController to maintain the Open Recent menu by sending a NSUrl with the location of the file to the NoteNewRecentDocumentURL method of the SharedDocumentController.

Далее необходимо переопределить OpenFile метод делегата приложения, чтобы открыть любой файл, выбираемый пользователем из меню Открыть последние .Next, you need to override the OpenFile method of the app delegate to open any file that the user selects from the Open Recent menu. Например:For example:

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

Если true файл можно открыть, возвращается значение, false а для пользователя отображается встроенное предупреждение о том, что не удалось открыть файл.Return true if the file can be opened, else return false and a built-in warning will be displayed to the user that the file could not be opened.

Так как имя файла и путь, возвращаемые из меню Открыть последние , могут содержать пробелы, необходимо надлежащим образом отэкранированить этот символ NSUrl перед созданием, иначе возникнет ошибка.Because the filename and path returned from the Open Recent menu, might include a space, we need to properly escape this character before creating a NSUrl or we will get an error. Мы делаем это с помощью следующего кода:We do that with the following code:

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

Наконец, мы создаем NSUrl объект, указывающий на файл, и используем вспомогательный метод в делегате приложения, чтобы открыть новое окно и загрузить в него файл:Finally, we create a NSUrl that points to the file and use a helper method in the app delegate to open a new window and load the file into it:

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

Чтобы извлечь все вместе, давайте рассмотрим пример реализации в файле AppDelegate.CS :To pull everything together, let's take a look at an example implementation in an AppDelegate.cs file:

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

В зависимости от требований приложения пользователю может быть нежелательно открывать один и тот же файл одновременно в нескольких окнах.Based on the requirements of your app, you might not want the user to open the same file in more than one window at the same time. В нашем примере приложения, если пользователь выбирает уже открытый файл (в открытом или открытом виде).In our example app, if the user chooses a file that is already open (either from the Open Recent or Open.. пункты меню), окно, содержащее файл, переносится на передний план.menu items), the window that contains the file is brought to the front.

Для этого мы использовали следующий код в нашем вспомогательном методе:To accomplish this, we used the following code in our helper method:

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

Мы разработали наш ViewController класс для хранения пути к файлу в его Path свойстве.We designed our ViewController class to hold the path to the file in its Path property. Далее мы выполним циклический перебор всех открытых окон в приложении.Next, we loop through all currently open windows in the app. Если файл уже открыт в одном из окон, он переносится на передний план всех остальных окон с помощью:If the file is already open in one of the windows, it is brought to the front of all other windows using:

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

Если совпадений не найдено, открывается новое окно с загруженным файлом, и файл отмечается в меню Открыть недавно :If no match is found, a new window is opened with the file loaded and the file is noted in the Open Recent menu:

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

Работа с действиями настраиваемого окнаWorking with custom window actions

Точно так же, как встроенные действия первого респондента , которые поставляются до стандартных пунктов меню, можно создавать новые настраиваемые действия и связывать их с элементами меню в Interface Builder.Just like the built-in First Responder actions that come pre-wired to standard menu items, you can create new, custom actions and wire them to menu items in Interface Builder.

Сначала определите настраиваемое действие на одном из контроллеров окна приложения.First, define a custom action on one of your app's window controllers. Например:For example:

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

Затем дважды щелкните файл раскадровки приложения в панель решения , чтобы открыть его для редактирования в Interface Builder Xcode.Next, double-click the app's storyboard file in the Solution Pad to open it for editing in Xcode's Interface Builder. Выберите первый респондент в сцене приложения, а затем перейдите в инспектор атрибутов:Select the First Responder under the Application Scene, then switch to the Attributes Inspector:

Инспектор атрибутовThe Attributes Inspector

Нажмите кнопку в нижней части инспектора атрибутов, чтобы добавить новое настраиваемое действие: +Click the + button at the bottom of the Attributes Inspector to add a new custom action:

Добавление нового действияAdding a new action

Присвойте ему имя, совпадающее с именем настраиваемого действия, созданного на контроллере окна.Give it the same name as the custom action that you created on your window controller:

Изменение имени действияEditing the action name

Щелчок и перетаскивание пункта меню на первый респондент в сцене приложения.Control-click and drag from a menu item to the First Responder under the Application Scene. Из раскрывающегося списка выберите только что созданное действие (defineKeyword: в этом примере):From the popup list, select the new action you just created (defineKeyword: in this example):

Присоединение действияAttaching an action

Сохраните изменения в раскадровке и вернитесь в Visual Studio для Mac, чтобы синхронизировать изменения.Save the changes to the storyboard and return to Visual Studio for Mac to sync the changes. Если запустить приложение, элемент меню, в который вы подключили настраиваемое действие, будет автоматически включен или отключен (на основе окна с открытым действием), и выбор пункта меню приведет к срабатыванию действия:If you run the app, the menu item that you connected the custom action to will automatically be enabled/disabled (based on the window with the action being open) and selecting the menu item will fire off the action:

Тестирование нового действияTesting the new action

Добавление, изменение и удаление менюAdding, editing, and deleting menus

Как мы видели в предыдущих разделах, приложение Xamarin. Mac поставляется с предустановленным количеством меню и пунктов меню по умолчанию, которые будут автоматически активированы и реагировать на эти элементы управления пользовательского интерфейса.As we have seen in the previous sections, a Xamarin.Mac application comes with a preset number of default menus and menu 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.

Дважды щелкните файл Main. Storyboard в панель решения , чтобы открыть его для редактирования:Double-click the Main.storyboard file in the Solution Pad to open it for editing:

Изменение пользовательского интерфейса в XcodeEditing the UI in Xcode

Для нашего конкретного приложения Xamarin. Mac мы не будем использовать меню « вид по умолчанию», поэтому мы будем его удалить.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:

![Выбор пункта меню «Вид] » (menu-images/maint02.png "Выбор пункта меню «Вид") »Selecting the View menu item

Нажмите клавишу DELETE или BACKSPACE, чтобы удалить меню.Press delete or backspace 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:

Выделение нескольких элементовHighlighting multiple items

Перетащите элементы из родительского меню в подменю, в котором они сейчас находятся:Drag the items under the parent Menu from the sub-menu where they currently are:

Перетаскивание пунктов меню в родительское менюDragging menu items to the parent menu

Теперь меню должно выглядеть следующим образом:Your menu should now look like:

Элементы в новом расположенииThe items in the new location

Теперь можно перетащить подменю текст из меню Формат и поместить его в главное меню в меню Формат и окно :Next let's drag the Text sub-menu out from under the Format menu and place it on the main menu bar between the Format and Window menus:

Текстовое менюThe Text menu

Вернемся к меню Формат и удалим элемент вложенного меню Шрифт .Let's go back under the Format menu and delete the Font sub-menu item. Затем выберите меню Формат и переименуйте его "Шрифт":Next, select the Format menu and rename it "Font":

Меню «Шрифт»The Font menu

Теперь создадим настраиваемое меню предопределенных фраз, которое автоматически добавляется к тексту в представлении текста при их выборе.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:

Инспектор библиотекThe Library Inspector

Теперь выполним следующие действия, чтобы создать наше меню:Now let's do the following to create our menu:

  1. Перетащите пункт меню из инспектора библиотеки в строку меню между меню " текст " и " окно ":Drag a Menu Item from the Library Inspector onto the menu bar between the Text and Window menus:

    Выбор нового пункта меню в библиотекеSelecting a new menu item in the Library

  2. Переименуйте элемент "фразы":Rename the item "Phrases":

    Задание имени менюSetting the menu name

  3. Затем перетащите меню из инспектора библиотеки:Next drag a Menu from the Library Inspector:

    Выбор меню из библиотекиSelecting a menu from the Library

  4. Перетащите меню в созданный элемент меню и измените его имя на "фразы":Drop then Menu on the new Menu Item we just created and change its name to "Phrases":

    Изменение имени менюEditing the menu name

  5. Теперь переименуем три элемента меню "адрес", "Дата" и "приветствие":Now let's rename the three default Menu Items "Address", "Date," and "Greeting":

    Меню фразThe Phrases menu

  6. Добавим четвертый пункт меню , перетащив пункт меню из инспектора библиотеки и вызвав его «Signature»:Let's add a fourth Menu Item by dragging a Menu Item from the Library Inspector and calling it "Signature":

    Изменение имени пункта менюEditing the menu item name

  7. Сохраните изменения в строке меню.Save the changes to the menu bar.

Теперь создадим набор настраиваемых действий, чтобы новые элементы меню были доступны для C# кода.Now let's create a set of custom actions so that our new menu items are exposed to C# code. В Xcode давайте перейдем к представлению помощника :In Xcode let's switch to the Assistant view:

Создание необходимых действийCreating the required actions

Давайте выполним следующие действия.Let's do the following:

  1. Перетащите элемент управления из пункта меню адрес в файл AppDelegate. h .Control-drag from the Address menu item to the AppDelegate.h file.

  2. Переключите тип подключения на действие:Switch the Connection type to Action:

    Выбор типа действияSelecting the action type

  3. Введите имя "фрасеаддресс" и нажмите кнопку " подключить ", чтобы создать новое действие:Enter a Name of "phraseAddress" and press the Connect button to create the new action:

    Настройка действияConfiguring the action

  4. Повторите описанные выше шаги для пунктов меню Дата, Приветствиеи подпись .Repeat the above steps for the Date, Greeting, and Signature menu items:

    Завершенные действияThe completed actions

  5. Сохраните изменения в строке меню.Save the changes to the menu bar.

Далее нам нужно создать выход для нашего текстового представления, чтобы мы могли настроить его содержимое из кода.Next we need to create an outlet for our text view so that we can adjust its content from code. Выберите файл ViewController. h в редакторе помощника и создайте новую розетку с именем documentText:Select the ViewController.h file in the Assistant Editor and create a new outlet called documentText:

Создание розеткиCreating an outlet

Вернитесь к Visual Studio для Mac, чтобы синхронизировать изменения из Xcode.Return to Visual Studio for Mac to sync the changes from Xcode. Затем измените файл ViewController.CS и сделайте его следующим:Next edit the ViewController.cs file and make it look like the following:

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

Это предоставляет текст текстового представления за пределами ViewController класса и информирует делегат приложения о том, что окно получает или теряет фокус.This exposes the text of our text view outside of the ViewController class and informs the app delegate when the window gains or loses focus. Теперь измените файл AppDelegate.CS и сделайте его следующим:Now edit the AppDelegate.cs file and make it look like the following:

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

Здесь мы сделали AppDelegate разделяемый класс, чтобы мы могли использовать действия и возможности, определенные в Interface Builder.Here we've made the AppDelegate a partial class so that we can use the actions and outlets that we defined in Interface Builder. Мы также предоставляем, textEditor чтобы отвести трассировку о том, какое окно сейчас находится в фокусе.We also expose a textEditor to track which window is currently in focus.

Для работы с пользовательскими меню и элементами меню используются следующие методы:The following methods are used to handle our custom menu and menu items:

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

Теперь, если мы выполним приложение, все элементы в меню « фраза » будут активными и будут добавлять фразу «присвоить» к представлению текста, если они выбраны: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:

Пример выполняемого приложенияAn example of the app running

Теперь, когда у нас есть основы работы с строкой меню приложения, давайте взглянем на создание настраиваемого контекстного меню.Now that we have the basics of working with the application menu bar down, let's look at creating a custom contextual menu.

Создание меню из кодаCreating menus from code

Помимо создания меню и пунктов меню с Interface Builder Xcode, могут возникнуть ситуации, когда приложению Xamarin. Mac нужно создать, изменить или удалить меню, подменю или пункт меню из кода.In addition to creating menus and menu items with Xcode's Interface Builder, there might be times when a Xamarin.Mac app needs to create, modify, or remove a menu, sub-menu, or menu item from code.

В следующем примере создается класс для хранения сведений о пунктах меню и подменю, которые будут динамически создаваться в режиме реального времени:In the following example, a class is created to hold the information about the menu items and sub-menus that will be dynamically created on-the-fly:

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

Добавление меню и элементовAdding menus and items

Если этот класс определен, следующая подпрограммы будет анализировать коллекцию LanguageFormatCommandобъектов и рекурсивно создавать новые меню и пункты меню, добавляя их в конец существующего меню (созданного в Interface Builder), которое было передано:With this class defined, the following routine will parse a collection of LanguageFormatCommandobjects and recursively build new menus and menu items by appending them to the bottom of the existing menu (created in Interface Builder) that has been passed in:

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

Для любого LanguageFormatCommand объекта, имеющего пустое Title свойство, эта подпрограммы создает пункт меню разделителя (тонкая серая линия) между разделами меню:For any LanguageFormatCommand object that has a blank Title property, this routine creates a Separator menu item (a thin gray line) between menu sections:

menuItem = NSMenuItem.SeparatorItem;

Если указано название, то создается новый элемент меню с таким названием:If a title is provided, a new menu item with that title is created:

menuItem = new NSMenuItem (command.Title);

Если объект содержит дочерние LanguageFormatCommand объекты, то создается AssembleMenu подменю, и метод рекурсивно вызывается для создания этого меню: LanguageFormatCommandIf the LanguageFormatCommand object contains child LanguageFormatCommand objects, a sub-menu is created and the AssembleMenu method is recursively called to build out that menu:

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

Для любого нового пункта меню, не имеющего подменю, добавляется код для управления пунктом меню, выбранным пользователем:For any new menu item that does not have sub-menus, code is added to handle the menu item being selected by the user:

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

Тестирование создания менюTesting the menu creation

При наличии всего приведенного выше кода, если была создана следующая коллекция LanguageFormatCommand объектов:With all of the above code in place, if the following collection of LanguageFormatCommand objects were created:

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

И эта коллекция передается AssembleMenu функции (в меню Формат , установленном в качестве базового), будут созданы следующие динамические меню и пункты меню:And that collection passed to the AssembleMenu function (with the Format Menu set as the base), the following dynamic menus and menu items would be created:

Новые пункты меню в работающем приложенииThe new menu items in the running app

Удаление меню и элементовRemoving menus and items

Если нужно удалить любое меню или пункт меню из пользовательского интерфейса приложения, можно использовать RemoveItemAt метод NSMenu класса, указав для него Отсчитываемый от нуля индекс удаляемого элемента.If you need to remove any menu or menu item from the app's user interface, you can use the RemoveItemAt method of the NSMenu class simply by giving it the zero based index of the item to remove.

Например, чтобы удалить меню и пункты меню, созданные в приведенной выше подпрограмме, можно использовать следующий код:For example, to remove the menus and menu items created by the routine above, you could use the following code:

public void UnpopulateFormattingMenu(NSMenu menu) {

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

В приведенном выше коде первые четыре пункта меню создаются в Interface Builder и вне области, доступных в приложении, поэтому они не удаляются динамически.In the case of the code above, the first four menu items are created in Xcode's Interface Builder and aways available in the app, so they are not removed dynamically.

Контекстные менюContextual menus

Контекстные меню появляются, когда пользователь щелкает правой кнопкой мыши элемент в окне.Contextual menus appear when the user right-clicks or control-clicks an item in a window. По умолчанию некоторые элементы пользовательского интерфейса, встроенные в macOS, уже имеют вложенные контекстные меню (например, представление текста).By default, several of the UI elements built into macOS 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.

Давайте изменим файл Main. Storyboard в Xcode и добавим окно окна в нашу структуру, присвойте его классу значение "нспанел" в инспекторе удостоверений, добавьте новый элемент помощника в меню окно и прикрепите его к новому окно, использующее показ перехода:Let's edit our Main.storyboard file in Xcode and add a Window window to our design, set its Class to "NSPanel" in the Identity Inspector, add a new Assistant item to the Window menu, and attach it to the new window using a Show Segue:

Установка типа переходаSetting the segue type

Давайте выполним следующие действия.Let's do the following:

  1. Перетащите метку из инспектора библиотек в окно панели и задайте для его текста значение "свойство":Drag a Label from the Library Inspector onto the Panel window and set its text to "Property":

    Изменение значения меткиEditing the label's value

  2. Затем перетащите меню из инспектора библиотек на контроллер представления в иерархии представлений и переименуйте три элемента меню: документ, текст и Шрифт.Next drag a Menu from the Library Inspector onto the View Controller in the View Hierarchy and rename the three default menu items Document, Text and Font:

    Обязательные пункты менюThe required menu items

  3. Теперь перетащите элемент управления из метки свойства в меню:Now control-drag from the Property Label onto the Menu:

    Перетаскивание для создания переходаDragging to create a segue

  4. Во всплывающем диалоговом окне выберите меню:From the popup dialog, select Menu:

    Установка типа переходаSetting the segue type

  5. В инспекторе удостоверенийзадайте для класса контроллера представления значение "панелвиевконтроллер":From the Identity Inspector, set the View Controller's class to "PanelViewController":

    Установка класса переходаSetting the segue class

  6. Переключитесь обратно на Visual Studio для Mac синхронизации, а затем вернитесь в Interface Builder.Switch back to Visual Studio for Mac to sync, then return to Interface Builder.

  7. Перейдите в Редактор помощника и выберите файл панелвиевконтроллер. h .Switch to the Assistant Editor and select the PanelViewController.h file.

  8. Создайте действие для пункта меню документа с именем propertyDocument:Create an action for the Document menu item called propertyDocument:

    Настройка действияConfiguring the action

  9. Повторите создание действий для остальных пунктов меню:Repeat creating actions for the remaining menu items:

    Необходимые действияThe required actions

  10. Наконец, создайте выход для метки свойства с именем propertyLabel:Finally create an outlet for the Property Label called propertyLabel:

    Настройка розеткиConfiguring the outlet

  11. Сохраните изменения и вернитесь в Visual Studio для Mac для синхронизации с Xcode.Save your changes and return to Visual Studio for Mac to sync with Xcode.

Измените файл PanelViewController.CS и добавьте следующий код:Edit the PanelViewController.cs file and add the following code:

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

Теперь, если мы запустим приложение и щелкнули правой кнопкой мыши метку свойства на панели, мы увидим настраиваемое контекстное меню.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:

Выполнение контекстного менюThe contextual menu running

Теперь рассмотрим создание меню строки состояния.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. Строка состояния на уровне системы находится в правой части строки меню приложения и является единственной строкой состояния, которая в настоящее время доступна в macOS.The system-wide status bar resides at the right side of the application menu bar and is the only Status Bar currently available in macOS.

Давайте изменим наш файл AppDelegate.CS и DidFinishLaunching создадим метод следующим образом:Let's edit our AppDelegate.cs file and make the DidFinishLaunching method look like the following:

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;предоставляет нам доступ к строке состояния на уровне системы.NSStatusBar statusBar = NSStatusBar.SystemStatusBar; gives us access to the system-wide status bar. var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable);создает новый элемент строки состояния.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:

Меню строки состояния работаетThe status bar menu running

Теперь давайте взглянем на создание пользовательских элементов меню Dock.Next, let's look at creating custom dock menu items.

Настраиваемые меню закрепленияCustom dock menus

Меню Dock (Закрепляемое) отображается для приложения Mac, когда пользователь щелкает правой кнопкой мыши значок приложения на панели Dock.The dock menu appears for you Mac application when the user right-clicks or control-clicks the application's icon in the dock:

Пользовательское меню закрепленияA custom dock menu

Давайте создадим пользовательское меню Dock для нашего приложения, выполнив следующие действия.Let's create a custom dock menu for our application by doing the following:

  1. В Visual Studio для Mac щелкните правой кнопкой мыши проект приложения и выберите Добавить > новый файл... В диалоговом окне новый файл выберите Xamarin. Mac > пустое определение интерфейса, используйте "доккмену" в качестве имени и нажмите кнопку " создать ", чтобы создать новый файл доккмену. XIB :In Visual Studio for Mac, right-click on the application's project and select Add > New File... From the new file dialog, select Xamarin.Mac > Empty Interface Definition, use "DockMenu" for the Name and click the New button to create the new DockMenu.xib file:

    Добавление пустого определения интерфейсаAdding an empty interface definition

  2. В панель решениядважды щелкните файл доккмену. XIB , чтобы открыть его для редактирования в Xcode.In the Solution Pad, 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

    Разметка ПОЛЬЗОВАТЕЛЬСКОГО интерфейсаLaying out the UI

  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. Прокрутите вниз и найдите phraseAddress: действие.Scroll down and find the phraseAddress: action. Перетащите линию из круга для этого действия в пункт меню " адрес ":Drag a line from the circle on that action to the Address menu item:

    Перетаскивание для связывания действияDragging to wire up an action

  4. Повторите все остальные пункты меню, присоединив их к соответствующим действиям:Repeat for all of the other menu items attaching them to their corresponding actions:

    Необходимые действияThe required actions

  5. Затем выберите приложение в иерархии интерфейсов.Next, select the Application in the Interface Hierarchy. В инспекторе подключенийперетащите линию из круга в dockMenu розетке в меню, которое мы только что создали:In the Connection Inspector, drag a line from the circle on the dockMenu outlet to the menu we just created:

    Перетаскивание проводаDragging the wire up the outlet

  6. Сохраните изменения и вернитесь в Visual Studio для Mac для синхронизации с Xcode.Save your changes and switch back to Visual Studio for Mac to sync with Xcode.

  7. Дважды щелкните файл info. plist , чтобы открыть его для редактирования:Double-click the Info.plist file to open it for editing:

    Редактирование файла info.plistEditing the Info.plist file

  8. Перейдите на вкладку источник в нижней части экрана:Click the Source tab at the bottom of the screen:

    Выбор представления источникаSelecting the Source view

  9. Нажмите кнопку Добавить новую запись, нажмите зеленую кнопку со знаком «плюс», задайте для свойства имя «аппледоккмену» и значение «доккмену» (имя нашего нового XIB-файла без расширения):Click Add new entry, click the green plus button, set the property name to "AppleDockMenu" and the value to "DockMenu" (the name of our new .xib file without the extension):

    Добавление элемента доккменуAdding the DockMenu item

Теперь, если мы запустим приложение и щелкнули его правой кнопкой мыши на значке закрепления, отобразятся новые пункты меню:Now if we run our application and right-click on its icon in the Dock, our new menu items will be displayed:

Пример работающего меню DockAn example of the dock menu running

Если выбрать один из пользовательских элементов в меню, текст в нашем текстовом представлении будет изменен.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. Измените файл Main. Storyboard в Xcode и перетащите всплывающую кнопку из инспектора библиотек в окно панели , созданное в разделе контекстных меню :Edit the Main.storyboard file in Xcode and drag a Popup Button from the Library Inspector onto the Panel window we created in the Contextual Menus section:

    Добавление всплывающей кнопкиAdding a popup button

  2. Добавьте новый пункт меню и задайте для заголовков элементов во всплывающем окне: Адрес, Дата, Приветствиеи подписьAdd a new menu item and set the titles of the Items in the Popup to: Address, Date, Greeting, and Signature

    Настройка пунктов менюConfiguring the menu items

  3. Теперь подключим новые пункты меню к существующим действиям, созданным для нашего пользовательского меню в разделе Добавление, изменение и удаление меню выше.Next, let's connect our new menu items to the 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. Прокрутите вниз и найдите phraseAddress: действие.Scroll down and find the phraseAddress: action. Перетащите линию из круга для этого действия в пункт меню " адрес ":Drag a line from the circle on that action to the Address menu item:

    Перетаскивание для связывания действияDragging to wire up an action

  4. Повторите все остальные пункты меню, присоединив их к соответствующим действиям:Repeat for all of the other menu items attaching them to their corresponding actions:

    Все необходимые действияAll required actions

  5. Сохраните изменения и вернитесь в Visual Studio для Mac для синхронизации с Xcode.Save your changes and switch back to Visual Studio for Mac 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:

Пример выполняемого всплывающего окнаAn example of the popup running

Вы можете создавать и работать с раскрывающимися списками точно так же, как всплывающие кнопки.You can create and work with pull-down lists in the exact same way as pop-up buttons. Вместо присоединения к существующему действию можно создать собственные пользовательские действия, как и для нашего контекстного меню в разделе контекстных меню .Instead of attaching to existing action, you could create your own custom actions just like we did for our contextual menu in the Contextual Menus section.

СводкаSummary

В этой статье подробно рассматривается работа с меню и элементами меню в приложении Xamarin. Mac.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.