Nabídky v Xamarin.Mac

Tento článek popisuje práci s nabídkami v aplikaci Xamarin.Mac. Popisuje vytváření a údržbu nabídek a položek nabídek v Xcode a Interface Builderu a práci s nimi programově.

Při práci s C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným nabídkám Cocoa, ve Objective-C kterých vývojář pracuje a Xcode. Vzhledem k tomu, že se Xamarin.Mac integruje přímo s Xcode, můžete pomocí Tvůrce rozhraní Xcode vytvářet a udržovat položky nabídek, nabídek a položek nabídek (nebo je volitelně vytvářet přímo v kódu jazyka C#).

Nabídky jsou nedílnou součástí uživatelského prostředí aplikace pro Mac a běžně se zobrazují v různých částech uživatelského rozhraní:

  • Řádek nabídek aplikace – Toto je hlavní nabídka, která se zobrazí v horní části obrazovky pro každou aplikaci pro Mac.
  • Místní nabídky – Zobrazí se, když uživatel klikne pravým tlačítkem myši nebo stisknutou stisknutou položku v okně.
  • Stavový řádek – Jedná se o oblast na pravé straně řádku nabídek aplikace, která se zobrazí v horní části obrazovky (vlevo od hodin řádku nabídek) a při přidávání položek doleva.
  • Nabídka Dok – nabídka pro každou aplikaci v doku, která se zobrazí, když uživatel klikne pravým tlačítkem nebo stisknutou klávesou CONTROL klikne na ikonu aplikace nebo když uživatel klikne na ikonu levým tlačítkem a podrží tlačítko myši.
  • Automaticky otevírané tlačítko a rozevírací seznamy – automaticky otevírané tlačítko zobrazí vybranou položku a zobrazí seznam možností, ze které můžete vybrat po kliknutí uživatelem. Rozevírací seznam je typ automaticky otevíraného tlačítka, které se obvykle používá pro výběr příkazů specifických pro kontext aktuálního úkolu. Obě můžou být zobrazeny kdekoli v okně.

An example menu

V tomto článku se podíváme na základy práce s panely nabídek Cocoa, nabídkami a položkami nabídek v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste si nejprve prošli článek Hello, Mac , konkrétně úvod do Xcode a Tvůrce rozhraní a výstupy a akce , protože se zabývá klíčovými koncepty a technikami, které budeme používat v tomto článku.

Můžete se také podívat na třídy a metody v jazyce C#, které jsou uvedeny v Objective-C oddílu dokumentu Internals Xamarin.Mac, vysvětluje RegisterExport a atributy používané k připojení tříd jazyka C# k Objective-C objektům a prvkům uživatelského rozhraní.

Řádek nabídek aplikace

Na rozdíl od aplikací běžících v operačním systému Windows, kde každé okno může mít připojený vlastní řádek nabídek, má každá aplikace spuštěná v systému macOS jeden řádek nabídek, který běží v horní části obrazovky, který se používá pro každé okno v dané aplikaci:

A menu bar

Položky na tomto řádku nabídek se aktivují nebo deaktivují na základě aktuálního kontextu nebo stavu aplikace a jeho uživatelského rozhraní v libovolném okamžiku. Například: Pokud uživatel vybere textové pole, budou položky v nabídce Úpravy povolené, například Kopírovat a Vyjmout.

Podle Apple a ve výchozím nastavení mají všechny aplikace macOS standardní sadu nabídek a položek nabídek, které se zobrazují na řádku nabídek aplikace:

  • Nabídka Apple – Tato nabídka poskytuje přístup k systémovým položkám, které jsou uživatelům k dispozici vždy bez ohledu na to, jaká aplikace je spuštěná. Vývojář tyto položky nemůže změnit.
  • Nabídka aplikace – Tato nabídka zobrazuje název aplikace tučně a pomáhá uživateli identifikovat, která aplikace je aktuálně spuštěná. Obsahuje položky, které se vztahují na aplikaci jako celek, a ne na daný dokument nebo proces, jako je ukončení aplikace.
  • Nabídka Soubor – Položky používané k vytvoření, otevření nebo uložení dokumentů, se kterými vaše aplikace pracuje. Pokud vaše aplikace není založená na dokumentech, můžete tuto nabídku přejmenovat nebo odebrat.
  • Nabídka Upravit – Obsahuje příkazy, jako je Vyjmout, Kopírovat a Vložit , které slouží k úpravám nebo úpravám prvků v uživatelském rozhraní aplikace.
  • Nabídka Formát – Pokud aplikace pracuje s textem, obsahuje tato nabídka příkazy pro úpravu formátování tohoto textu.
  • Nabídka Zobrazení – Obsahuje příkazy, které ovlivňují zobrazení obsahu (zobrazení) v uživatelském rozhraní aplikace.
  • Nabídky specifické pro aplikaci – Jedná se o nabídky specifické pro vaši aplikaci (například nabídku záložek pro webový prohlížeč). Měly by se zobrazit mezi nabídkami Zobrazení a Okna na panelu.
  • Nabídka Okna – Obsahuje příkazy pro práci s okny v aplikaci a také seznam otevřených oken.
  • Nabídka Nápověda – Pokud vaše aplikace poskytuje nápovědu na obrazovce, měla by být nabídka Nápověda na panelu vpravo.

Další informace o řádku nabídek aplikace a standardních nabídkách a položkách nabídek najdete v pokynech pro lidské rozhraní společnosti Apple.

Výchozí řádek nabídek aplikace

Pokaždé, když vytvoříte nový projekt Xamarin.Mac, automaticky získáte standardní výchozí řádek nabídek aplikace s typickými položkami, které by aplikace pro macOS normálně měla (jak je popsáno v předchozí části). Výchozí řádek nabídek vaší aplikace se definuje v souboru Main.storyboard (spolu se zbytkem uživatelského rozhraní vaší aplikace) v oblasti řešení v oblasti řešení:

Select the main storyboard

Poklikáním otevřete soubor Main.storyboard pro úpravy v Tvůrci rozhraní Xcode a zobrazí se rozhraní editoru nabídek:

Editing the UI in Xcode, showing the Main dot storyboard.

Zde můžeme kliknout na položky, jako je například otevřít položku nabídky v nabídce Soubor , upravit nebo upravit její vlastnosti v Inspektoru atributů:

Editing a menu's attributes

Dále v tomto článku se seznámíme s přidáváním, úpravami a odstraňováním nabídek a položek. Prozatím chceme jenom zjistit, jaké nabídky a položky nabídek jsou ve výchozím nastavení dostupné a jak byly automaticky zpřístupněny kódu prostřednictvím sady předdefinovaných výstupů a akcí (další informace najdete v dokumentaci k výstupům a akcím ).

Pokud například klikneme na inspektor Připojení ion pro položku nabídky Otevřít, uvidíme, že je automaticky připojena k openDocument: akci:

Viewing the attached action

Pokud vyberete první respondér v hierarchii rozhraní a v Připojení ion Inspectoru se posunete dolů a zobrazí se definice openDocument: akce, ke které je položka nabídky Otevřít připojena (spolu s několika dalšími výchozími akcemi pro aplikaci, která jsou a nejsou automaticky připojena k ovládacím prvkům):

Viewing all attached actions

Proč je to důležité? V další části se dozvíte, jak tyto automaticky definované akce fungují s dalšími prvky uživatelského rozhraní Cocoa, které automaticky povolí a zakáže položky nabídek, a také poskytují integrované funkce pro položky.

Později tyto předdefinované akce použijeme k povolení a zakázání položek z kódu a poskytnutí vlastních funkcí při jejich výběru.

Předdefinované funkce nabídky

Pokud jste před přidáním jakýchkoli položek uživatelského rozhraní nebo kódu spustili nově vytvořenou aplikaci Xamarin.Mac, všimnete si, že některé položky jsou automaticky připojené a povolené (s plnou funkčností automaticky předdefinovanou), jako je například položka Ukončit v nabídce aplikace :

An enabled menu item

I když jiné položky nabídky, jako jsou vyjmutí, kopírování a vložení , nejsou:

Disabled menu items

Zastavme aplikaci a poklikáním na soubor Main.storyboard v oblasti řešení ji otevřete pro úpravy v Tvůrci rozhraní Xcode. Potom přetáhněte textové zobrazení z knihovny do kontroleru zobrazení okna v editoru rozhraní:

Selecting a Text View from the Library

V Editoru omezení připneme textové zobrazení na hrany okna a nastavíme ho tam, kde se zvětší a zmenší s oknem kliknutím na všechny čtyři červené paprsky v horní části editoru a kliknutím na tlačítko Přidat 4 omezení:

Editing the contraints

Uložte změny návrhu uživatelského rozhraní a přepněte zpět Visual Studio pro Mac, aby se změny synchronizovaly s projektem Xamarin.Mac. Teď spusťte aplikaci, zadejte do textového zobrazení nějaký text, vyberte ho a otevřete nabídku Upravit :

The menu items are automatically enabled/disabled

Všimněte si, jak jsou položky Vyjmout, Kopírovat a Vložit automaticky povoleny a plně funkční, a to vše bez psaní jednoho řádku kódu.

Co se tu děje? Nezapomeňte, že předdefinované předdefinované akce, které se připojují k výchozím položkám nabídky (jak je uvedeno výše), většina prvků uživatelského rozhraní Cocoa, které jsou součástí macOS, mají integrované hooky ke konkrétním akcím (například copy:). Takže když jsou přidány do okna, aktivní a vybrané, odpovídající položka nabídky nebo položky připojené k této akci jsou automaticky povoleny. Pokud uživatel vybere tuto položku nabídky, funkce integrované do prvku uživatelského rozhraní se zavolá a spustí, a to vše bez zásahu vývojáře.

Povolení a zakázání nabídek a položek

Ve výchozím nastavení se pokaždé, když dojde k události uživatele, NSMenu automaticky povolí a zakáže každou viditelnou nabídku a položku nabídky na základě kontextu aplikace. Položku můžete povolit nebo zakázat třemi způsoby:

  • Automatické povolení nabídky – Položka nabídky je povolena, pokud NSMenu může najít odpovídající objekt, který reaguje na akci, na kterou je položka připojena kabelem. Například výše uvedené textové zobrazení, které mělo předdefinované připojení k copy: akci.
  • Vlastní akce a validateMenuItem: – Pro libovolnou položku nabídky, která je svázaná s oknem nebo vlastní akcí kontroleru zobrazení, můžete validateMenuItem: přidat akci a ručně povolit nebo zakázat položky nabídky.
  • Ruční povolení nabídky – Vlastnost každého z nich NSMenuItem můžete ručně nastavit Enabled tak, aby se jednotlivé položky v nabídce povolily nebo zakázaly jednotlivě.

Chcete-li zvolit systém, nastavte AutoEnablesItems vlastnost NSMenu. true je automatické (výchozí chování) a false je ruční.

Důležité

Pokud se rozhodnete použít ruční povolení nabídky, žádná z položek nabídky, dokonce i ty, které řídí třídy AppKit jako NSTextView, se aktualizují automaticky. Budete zodpovědní za povolení a zakázání všech položek ručně v kódu.

Použití validateMenuItem

Jak je uvedeno výše, pro libovolnou položku nabídky, která je vázána na vlastní akci okna nebo zobrazení kontroleru, můžete přidat validateMenuItem: akci a ručně povolit nebo zakázat položky nabídky.

V následujícím příkladu Tag bude vlastnost použita k rozhodnutí o typu položky nabídky, která bude povolena nebo zakázána validateMenuItem: akcí na základě stavu vybraného textu v objektu NSTextView. Vlastnost Tag byla nastavena v Tvůrci rozhraní pro každou položku nabídky:

Setting the Tag property

A do kontroleru zobrazení se přidal následující kód:

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

Když se tento kód spustí a v NSTextViewřadiči zobrazení nejsou vybrány žádné texty, jsou zakázány dvě položky nabídky obtékání (i když jsou připojené k akcím v kontroleru zobrazení):

Showing disabled items

Pokud je vybraný oddíl textu a nabídka se znovu otevře, budou k dispozici dvě položky zalamované nabídky:

Showing enabled items

Povolení a reakce na položky nabídky v kódu

Jak jsme viděli výše, stačí do návrhu uživatelského rozhraní přidat specifické prvky uživatelského rozhraní Cocoa (například textové pole), několik výchozích položek nabídky se povolí a bude fungovat automaticky, aniž byste museli psát žádný kód. Teď se podíváme na přidání vlastního kódu jazyka C# do projektu Xamarin.Mac, abychom povolili položku nabídky a poskytli funkce, když ji uživatel vybere.

Řekněme například, že chceme, aby uživatel mohl vybrat složku pomocí položky Otevřít v nabídce Soubor . Vzhledem k tomu, že chceme, aby to byla funkce pro celou aplikaci, a ne jen na prvek pro poskytnutí okna nebo uživatelského rozhraní, přidáme kód, který to zpracuje delegátovi aplikace.

V oblasti řešení poklikáním AppDelegate.CS otevřete soubor pro úpravy:

Selecting the app delegate

Pod metodu DidFinishLaunching přidejte následující kód:

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

Teď spustíme aplikaci a otevřete nabídku Soubor :

The File menu

Všimněte si, že položka nabídky Otevřít je teď povolená. Pokud ho vybereme, zobrazí se otevřené dialogové okno:

An open dialog

Pokud klikneme na tlačítko Otevřít , zobrazí se naše zpráva s upozorněním:

An example dialog message

Hlavní řádek zde byl [Export ("openDocument:")], říká NSMenu , že naše AppDelegate má metodu void OpenDialog (NSObject sender) , která reaguje na openDocument: akci. Pokud si budete pamatovat výše, položka nabídky Otevřít se automaticky připojí k této akci ve výchozím nastavení v Tvůrci rozhraní:

Viewing the attached actions

Teď se podíváme na vytvoření vlastní nabídky, položek nabídek a akcí a reagování na ně v kódu.

Práce s otevřenou poslední nabídkou

Ve výchozím nastavení obsahuje nabídka Soubor položku Otevřít poslední, která sleduje posledních několik souborů, které uživatel otevřel ve vaší aplikaci. Pokud vytváříte aplikaci Xamarin.Mac založenou NSDocument na Xamarin.Mac, bude tato nabídka automaticky zpracována. Pro jakýkoli jiný typ aplikace Xamarin.Mac budete zodpovědní za správu a odpovídání na tuto položku nabídky ručně.

Pokud chcete nabídku Otevřít poslední otevřít ručně zpracovat, musíte nejprve informovat, že byl otevřen nebo uložen nový soubor pomocí následujícího příkazu:

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

I když vaše aplikace nepoužívá NSDocuments, stále používáte NSDocumentController k údržbě nabídky Otevřít poslední odesláním NSUrl umístění souboru metodě NoteNewRecentDocumentURLSharedDocumentControllersouboru .

Dále je potřeba přepsat metodu OpenFile delegáta aplikace, aby se otevřel libovolný soubor, který uživatel vybere z nabídky Otevřít poslední . Příklad:

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

Vraťte true se, pokud je možné soubor otevřít, jinak se vrátí false a uživateli se zobrazí předdefinované upozornění, že soubor nelze otevřít.

Vzhledem k tomu, že název souboru a cesta vrácené z nabídky Otevřít poslední , může obsahovat mezeru, musíme tento znak před vytvořením nebo NSUrl se zobrazí chyba. Provedeme to pomocí následujícího kódu:

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

Nakonec vytvoříme odkazující NSUrl na soubor a použijeme pomocnou metodu v delegátu aplikace k otevření nového okna a načtení souboru do něj:

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

Abychom všechno strhli dohromady, podívejme se na ukázkovou implementaci v souboru AppDelegate.cs :

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

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

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

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

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

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

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

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

                // Is the file already open?
                for(int n=0; n<NSApplication.SharedApplication.Windows.Length; ++n) {
                    var content = NSApplication.SharedApplication.Windows[n].ContentViewController as ViewController;
                    if (content != null && path == content.FilePath) {
                        // Bring window to front
                        NSApplication.SharedApplication.Windows[n].MakeKeyAndOrderFront(this);
                        return true;
                    }
                }

                // Get new window
                var storyboard = NSStoryboard.FromName ("Main", null);
                var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

                // Display
                controller.ShowWindow(this);

                // Load the text into the window
                var viewController = controller.Window.ContentViewController as ViewController;
                viewController.Text = File.ReadAllText(path);
                viewController.SetLanguageFromPath(path);
                viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
                viewController.View.Window.RepresentedUrl = url;

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

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

            // Return results
            return good;
        }
        #endregion

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

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

                if (url != null) {
                    // Open the document in a new window
                    OpenFile (url);
                }
            }
        }
        #endregion
    }
}

V závislosti na požadavcích aplikace možná nebudete chtít, aby uživatel současně otevřel stejný soubor ve více než jednom okně. Pokud uživatel v naší ukázkové aplikaci zvolí soubor, který je již otevřený (buď z položek nabídky Otevřít poslední , nebo Otevřít), okno obsahující soubor se přenese do popředí.

K tomu jsme v pomocné metodě použili následující kód:

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

Naši třídu jsme navrhli ViewController tak, aby držela cestu k souboru ve své Path vlastnosti. V dalším kroku projdeme všechna aktuálně otevřená okna v aplikaci. Pokud je soubor již otevřený v jednom z oken, přenese se na přední straně všech ostatních oken pomocí:

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

Pokud se nenajde žádná shoda, otevře se nové okno se načteným souborem a soubor se zaznačí v nabídce Otevřít poslední :

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

Práce s vlastními akcemi oken

Stejně jako předdefinované akce prvního respondéru , které jsou předem připojené ke standardním položkám nabídek, můžete vytvořit nové, vlastní akce a připojit je k položkám nabídky v Tvůrci rozhraní.

Nejprve definujte vlastní akci na jednom z kontrolerů oken vaší aplikace. Příklad:

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

Potom poklikejte na soubor scénáře aplikace v oblasti řešení a otevřete ho pro úpravy v Tvůrci rozhraní Xcode. Vyberte první respondér ve scéně aplikace a pak přepněte na Inspektor atributů:

The Attributes Inspector

Kliknutím na + tlačítko v dolní části inspektoru atributů přidejte novou vlastní akci:

Adding a new action

Pojmenujte ho stejně jako vlastní akci, kterou jste vytvořili v kontroleru okna:

Editing the action name

Control-click and drag from a menu item to the First Responder under the Application Scene. V automaticky otevírané nabídce vyberte novou akci, kterou jste právě vytvořili (defineKeyword: v tomto příkladu):

Attaching an action

Uložte změny do scénáře a vraťte se do Visual Studio pro Mac, aby se změny synchronizovaly. Pokud spustíte aplikaci, položka nabídky, ke které jste vlastní akci připojili, se automaticky povolí nebo zakáže (na základě okna s otevřenou akcí) a výběrem položky nabídky se aktivuje akce:

Testing the new action

Přidávání, úpravy a odstraňování nabídek

Jak jsme viděli v předchozích částech, aplikace Xamarin.Mac obsahuje přednastavený počet výchozích nabídek a položek nabídek, na které se konkrétní ovládací prvky uživatelského rozhraní automaticky aktivují a reagují. Viděli jsme také, jak do aplikace přidat kód, který umožní tyto výchozí položky a odpovídá na ně.

V této části se podíváme na odebrání položek nabídky, které nepotřebujeme, přeuspořádání nabídek a přidávání nových nabídek, položek nabídek a akcí.

Dvakrát klikněte na soubor Main.storyboard v oblasti řešení a otevřete ho pro úpravy:

Double-clicking the storyboard file to edit the UI in Xcode.

Pro naši konkrétní aplikaci Xamarin.Mac nebudeme používat výchozí nabídku Zobrazení , takže ji odebereme. V hierarchii rozhraní vyberte položku nabídky Zobrazení, která je součástí hlavního řádku nabídek:

Selecting the View menu item

Stisknutím klávesy Delete nebo Backspace nabídku odstraňte. V dalším kroku nebudeme používat všechny položky v nabídce Formát a chceme přesunout položky, které budeme používat mimo podsítě. V hierarchii rozhraní vyberte následující položky nabídky:

Highlighting multiple items

Přetáhněte položky pod nadřazenou nabídku z podadresní nabídky , kde jsou aktuálně:

Dragging menu items to the parent menu

Nabídka by teď měla vypadat takto:

The items in the new location

Teď přetáhneme dílčí nabídku Text z nabídky Formát a umístíme ji do hlavního řádku nabídek mezi nabídkami Formát a Okno :

The Text menu

Vraťme se zpátky pod nabídku Formát a odstraňme položku dílčí nabídky Písmo . Dále vyberte nabídku Formát a přejmenujte ho na Písmo:

The Font menu

V dalším kroku vytvoříme vlastní nabídku předdefinovaných frází, které se automaticky přidají k textu v textovém zobrazení, když jsou vybrané. Do vyhledávacího pole v dolní části inspektoru knihovny zadejte "menu". Usnadníte tak hledání a práci se všemi prvky uživatelského rozhraní nabídky:

The Library Inspector

Teď vytvoříme naši nabídku takto:

  1. Přetáhněte položku nabídky z nástroje Library Inspector do řádku nabídek mezi nabídkami Text a Okno:

    Selecting a new menu item in the Library

  2. Přejmenujte položku "Fráze":

    Setting the menu name

  3. Potom přetáhněte nabídku z inspektoru knihovny:

    Selecting a menu from the Library

  4. Přetáhněte nabídku na novou položku nabídky, kterou jsme právě vytvořili, a změňte její název na "Fráze":

    Editing the menu name

  5. Teď přejmenujme tři výchozí položky nabídky Address (Adresa), Date (Datum) a Greeting (Pozdrav):

    The Phrases menu

  6. Pojďme přidat čtvrtou položku nabídky přetažením položky nabídky z inspektoru knihovny a jeho voláním "Podpis":

    Editing the menu item name

  7. Uložte změny do řádku nabídek.

Teď vytvoříme sadu vlastních akcí, aby byly naše nové položky nabídky zpřístupněny kódu jazyka C#. V Xcode přepneme do zobrazení Asistent :

Creating the required actions

Pojďme udělat toto:

  1. Control-drag from the Address menu item to the AppDelegate.h file.

  2. Přepněte typ Připojení ion na akci:

    Selecting the action type

  3. Zadejte název frázeAddress a stisknutím tlačítka Připojení vytvořte novou akci:

    Configuring the action by entering a name.

  4. Opakujte výše uvedené kroky pro položky nabídky Datum, Pozdrav a Podpis :

    The completed actions

  5. Uložte změny do řádku nabídek.

Dále potřebujeme vytvořit výstup pro textové zobrazení, abychom mohli upravit jeho obsah z kódu. V Editoru asistentů vyberte soubor ViewController.h a vytvořte novou zásuvku s názvem documentText:

Creating an outlet

Vraťte se do Visual Studio pro Mac, abyste synchronizovali změny z Xcode. Potom upravte soubor ViewController.cs a udělejte ho takto:

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

Tím se zpřístupní text našeho textového zobrazení mimo ViewController třídu a informuje delegáta aplikace, když okno získá nebo ztratí fokus. Teď upravte soubor AppDelegate.cs a udělejte ho takto:

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

Tady jsme vytvořili AppDelegate částečnou třídu, abychom mohli používat akce a výstupy, které jsme definovali v Tvůrci rozhraní. Zveřejňujeme textEditor také sledování, na které okno je aktuálně fokus.

K zpracování vlastní nabídky a položek nabídky se používají následující metody:

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

Když teď spustíme naši aplikaci, všechny položky v nabídce Fráze budou aktivní a při výběru této fráze se do textového zobrazení přidají:

An example of the app running

Teď, když máme základy práce s panelem nabídek aplikace dole, se podíváme na vytvoření vlastní kontextové nabídky.

Vytváření nabídek z kódu

Kromě vytváření nabídek a položek nabídek pomocí Tvůrce rozhraní Xcode může docházet k časům, kdy aplikace Xamarin.Mac potřebuje vytvořit, upravit nebo odebrat nabídku, dílčí nabídku nebo položku nabídky z kódu.

V následujícím příkladu se vytvoří třída, která bude obsahovat informace o položkách nabídky a dílčích nabídkách, které budou dynamicky vytvořeny za běhu:

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

Přidávání nabídek a položek

S touto třídou definovanou následující rutinou parsuje kolekci LanguageFormatCommandobjektů a rekurzivně sestaví nové nabídky a položky nabídek tak, že je připojí do dolní části existující nabídky (vytvořené v Tvůrci rozhraní), která byla předána:

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

Pro každý LanguageFormatCommand objekt, který má prázdnou Title vlastnost, tato rutina vytvoří položku nabídky Oddělovač (tenká šedá čára) mezi oddíly nabídek:

menuItem = NSMenuItem.SeparatorItem;

Pokud je název zadaný, vytvoří se nová položka nabídky s tímto názvem:

menuItem = new NSMenuItem (command.Title);

LanguageFormatCommand Pokud objekt obsahuje podřízené LanguageFormatCommand objekty, vytvoří se podnabídka a AssembleMenu metoda je rekurzivně volána k sestavení této nabídky:

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

Pro libovolnou novou položku nabídky, která nemá podnabídky, se přidá kód pro zpracování položky nabídky vybrané uživatelem:

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

Testování vytvoření nabídky

Pokud byla vytvořena následující kolekce LanguageFormatCommand objektů, je-li vytvořen veškerý výše uvedený kód:

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

A tato kolekce se předá AssembleMenu funkci (s nastavením nabídky Format jako základ), vytvoří se následující dynamické nabídky a položky nabídek:

The new menu items in the running app

Odebírání nabídek a položek

Pokud potřebujete z uživatelského rozhraní aplikace odebrat libovolnou nabídku nebo položku nabídky, můžete metodu NSMenu třídy jednoduše použít RemoveItemAt tak, že jí poskytnete nulový index položky, který chcete odebrat.

Pokud chcete například odebrat nabídky a položky nabídky vytvořené výše uvedenou rutinou, můžete použít následující kód:

public void UnpopulateFormattingMenu(NSMenu menu) {

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

V případě výše uvedeného kódu se první čtyři položky nabídky vytvoří v Tvůrci rozhraní Xcode a v aplikaci jsou pryč, takže se neodeberou dynamicky.

Místní nabídky

Místní nabídky se zobrazí, když uživatel klikne pravým tlačítkem myši nebo stisknutou stisknutou položku v okně. Ve výchozím nastavení má několik prvků uživatelského rozhraní integrovaných do systému macOS k nim připojené kontextové nabídky (například textové zobrazení). Někdy ale můžeme chtít vytvořit vlastní kontextové nabídky pro prvek uživatelského rozhraní, který jsme přidali do okna.

Pojďme upravit soubor Main.storyboard v Xcode a přidat okno okna do našeho návrhu, nastavit jeho třídu na NSPanel v Nástroji Identity Inspector, přidat novou položku Pomocníka do nabídky Okno a připojit ho k novému okně pomocí show Segue:

Setting the segue type in the Main dot storyboard file.

Pojďme udělat toto:

  1. Přetáhněte popisek z inspektoruknihovny do okna Panel a nastavte jeho text na Vlastnost:

    Editing the label's value

  2. Potom přetáhněte nabídku z nástroje Library Inspector do kontroleru zobrazení v hierarchii zobrazení a přejmenujte tři výchozí položky nabídky Dokument, Text a Písmo:

    The required menu items

  3. Teď ovládací prvek přetáhněte z popisku vlastnosti do nabídky:

    Dragging to create a segue

  4. V místním dialogovém okně vyberte Nabídku:

    Setting the segue type by selecting menu from Outlets in the Label context menu.

  5. V Kontrole identit nastavte třídu kontroleru zobrazení na PanelViewController:

    Setting the segue class

  6. Přepněte zpět na Visual Studio pro Mac, aby se synchronizoval, a pak se vraťte do Tvůrce rozhraní.

  7. Přepněte do Editoru asistentů a vyberte soubor PanelViewController.h .

  8. Vytvořte akci pro položku nabídky Dokument s názvem propertyDocument:

    Configuring the action named propertyDocument.

  9. Opakujte vytváření akcí pro zbývající položky nabídky:

    Repeating actions for the remaining menu items.

  10. Nakonec vytvořte výstup pro popisek vlastnosti s názvem propertyLabel:

    Configuring the outlet

  11. Uložte změny a vraťte se do Visual Studio pro Mac pro synchronizaci s Xcode.

Upravte soubor PanelViewController.cs a přidejte následující kód:

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

Když teď spustíme aplikaci a klikneme pravým tlačítkem myši na popisek vlastnosti na panelu, zobrazí se naše vlastní kontextová nabídka. Pokud vybereme položku a položku z nabídky, hodnota popisku se změní:

The contextual menu running

Teď se podíváme na vytváření nabídek stavového řádku.

Nabídky stavového řádku

Nabídky stavového řádku zobrazují kolekci položek stavové nabídky, které poskytují interakci s uživatelem nebo jejich zpětnou vazbu, například nabídku nebo obrázek odrážející stav aplikace. Nabídka stavového řádku aplikace je povolená a aktivní, i když je aplikace spuštěná na pozadí. Stavový řádek na úrovni celého systému se nachází na pravé straně řádku nabídek aplikace a je jediným stavovým řádkem, který je aktuálně dostupný v systému macOS.

Pojďme upravit náš soubor AppDelegate.cs a nastavit metodu DidFinishLaunching takto:

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; poskytuje přístup k stavovém řádku na úrovni celého systému. var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable); vytvoří novou položku stavového řádku. Odtud vytvoříme nabídku a řadu položek nabídky a připojíme ji k položce stavového řádku, kterou jsme právě vytvořili.

Pokud spustíme aplikaci, zobrazí se nová položka stavového řádku. Výběrem položky z nabídky změníte text v textovém zobrazení:

The status bar menu running

V dalším kroku se podíváme na vytvoření vlastních položek nabídky doku.

Vlastní nabídky dokování

Když uživatel klikne pravým tlačítkem myši nebo control klikne na ikonu aplikace v docku, zobrazí se nabídka doku pro aplikaci pro Mac:

A custom dock menu

Pojďme pro naši aplikaci vytvořit vlastní nabídku doku následujícím způsobem:

  1. V Visual Studio pro Mac klikněte pravým tlačítkem na projekt aplikace a vyberte Přidat>nový soubor... V dialogovém okně nový soubor vyberte Xamarin.Mac>Empty Interface Definition, jako název použijte DockMenu a kliknutím na tlačítko Nový vytvořte nový soubor DockMenu.xib:

    Adding an empty interface definition

  2. V oblasti řešení poklikejte na soubor DockMenu.xib a otevřete ho pro úpravy v Xcode. Vytvořte novou nabídku s následujícími položkami: Adresa, Datum, Pozdrav a Podpis

    Laying out the UI

  3. V dalším kroku propojíme nové položky nabídek s existujícími akcemi, které jsme vytvořili pro vlastní nabídku v části Přidávání, úpravy a odstraňování nabídek výše. Přepněte na Připojení ion Inspector a v hierarchii rozhraní vyberte první respondér. Posuňte se dolů a najděte phraseAddress: akci. Přetáhněte čáru z kruhu v této akci na položku nabídky Adresa :

    Dragging a line to the Address menu item.

  4. Opakujte postup pro všechny ostatní položky nabídky, které je připojují k odpovídajícím akcím:

    Repeating for other menu items attaching them to their corresponding actions.

  5. Dále vyberte aplikaci v hierarchii rozhraní. V inspektoru Připojení přetáhněte čáru z kruhu na výstupu dockMenu do nabídky, kterou jsme právě vytvořili:

    Dragging the wire up the outlet

  6. Uložte změny a přepněte zpátky na Visual Studio pro Mac, aby se synchronizovaly s Xcode.

  7. Poklikáním otevřete soubor Info.plist pro úpravy:

    Editing the Info.plist file

  8. Klikněte na kartu Zdroj v dolní části obrazovky:

    Selecting the Source view

  9. Klikněte na Přidat novou položku, klikněte na zelené tlačítko plus, nastavte název vlastnosti na AppleDockMenu a hodnotu na DockMenu (název našeho nového souboru .xib bez přípony):

    Adding the DockMenu item

Když teď spustíme naši aplikaci a klikneme pravým tlačítkem myši na její ikonu v Docku, zobrazí se nové položky nabídky:

An example of the dock menu running

Pokud vybereme jednu z vlastních položek z nabídky, text v našem textovém zobrazení se upraví.

Automaticky otevírané tlačítko a rozevírací seznamy

Automaticky otevírané tlačítko zobrazí vybranou položku a zobrazí seznam možností, ze které můžete vybrat po kliknutí uživatelem. Rozevírací seznam je typ automaticky otevíraného tlačítka, které se obvykle používá pro výběr příkazů specifických pro kontext aktuálního úkolu. Obě můžou být zobrazeny kdekoli v okně.

Pomocí následujícího příkazu vytvořte vlastní automaticky otevírané tlačítko pro naši aplikaci:

  1. Upravte soubor Main.storyboard v Xcode a přetáhněte překryvné tlačítko z Inspektoru knihovny do okna panelu, které jsme vytvořili v části Kontextové nabídky:

    Adding a popup button

  2. Přidání nové položky nabídky a nastavení názvů položek v místní nabídce na: Adresa, Datum, Pozdrav a Podpis

    Configuring the menu items

  3. V dalším kroku propojíme nové položky nabídky s existujícími akcemi, které jsme vytvořili pro vlastní nabídku v části Přidávání, úpravy a odstraňování nabídek výše. Přepněte na Připojení ion Inspector a v hierarchii rozhraní vyberte první respondér. Posuňte se dolů a najděte phraseAddress: akci. Přetáhněte čáru z kruhu v této akci na položku nabídky Adresa :

    Dragging to wire up an action

  4. Opakujte postup pro všechny ostatní položky nabídky, které je připojují k odpovídajícím akcím:

    All required actions

  5. Uložte změny a přepněte zpátky na Visual Studio pro Mac, aby se synchronizovaly s Xcode.

Když teď spustíme naši aplikaci a vybereme položku z místní nabídky, text v našem textovém zobrazení se změní:

An example of the popup running

Můžete vytvářet a pracovat s rozevíracími seznamy úplně stejným způsobem jako automaticky otevíraná tlačítka. Místo připojení k existující akci byste mohli vytvořit vlastní akce stejně jako v místní nabídce v části Kontextové nabídky.

Shrnutí

Tento článek se podrobně podíval na práci s nabídkami a položkami nabídek v aplikaci Xamarin.Mac. Nejprve jsme prozkoumali řádek nabídek aplikace a pak jsme se podívali na vytváření kontextových nabídek, dále jsme prozkoumali nabídky stavového řádku a vlastní dokovací nabídky. Nakonec jsme probrali místní nabídky a rozevírací seznamy.