Nabídky v Xamarin.Macu

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 Builder a práci s nimi prostřednictvím kódu programu.

Při práci s C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným nabídkám Cocoa, ve které vývojář pracuje a Objective-C Xcode. Vzhledem k tomu, že Xamarin.Mac se integruje přímo s Xcode, můžete použít Interface Builder Xcode k vytvoření a údržbě panelů nabídek, nabídek a položek nabídek (nebo je volitelně vytvořit přímo v kódu C#).

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

  • Řádek nabídek aplikace – hlavní nabídka, která se zobrazí v horní části obrazovky pro každou aplikaci systému Mac.
  • Kontextové nabídky – zobrazí se, když uživatel klikne pravým tlačítkem nebo klikne na položku v okně.
  • Stavový řádek – toto je oblast na pravé straně řádku nabídek aplikace, která se zobrazí v horní části obrazovky (nalevo od hodin řádku nabídek) a při přidání položek se zvětšuje doleva.
  • Nabídka Ukotvit – nabídka pro každou aplikaci v Docku, která se zobrazí, když uživatel klikne pravým tlačítkem nebo stiskne klávesu Control na ikonu aplikace nebo když uživatel klikne vlevo na ikonu a podrží tlačítko myši dolů.
  • Automaticky otevírané a rozevírací seznamy – Automaticky otevírané tlačítko zobrazí vybranou položku a zobrazí seznam možností, ze kterých si můžete vybrat, když na něj uživatel klikne. Rozevírací seznam je typ překryvového tlačítka, které se obvykle používá pro výběr příkazů specifických pro kontext aktuální úlohy. Obojí se může zobrazit kdekoli v okně.

Příklad nabídky

V tomto článku se budeme seznamovat se základy práce s pruhy nabídek, nabídkami a položkami nabídek Cocoa v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste si nejprve prošli článek Hello, Mac, konkrétně oddíly Úvod do Xcode a Interface Builder a Výstupy a Akce, protože se zabývá klíčovými koncepty a technikami, které budeme v tomto článku používat.

Možná se budete chtít podívat i na část dokumentu Exposing C# classes / methods to Objective-CExposing C# classes / methods to Objective-C která vysvětluje atributy a používané k připojení tříd jazyka C# k objektům a prvkům uživatelského RegisterExportObjective-C rozhraní.

Řádek nabídek aplikace

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

Řádek nabídek

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

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

  • Nabídka Apple – Tato nabídka poskytuje přístup k položkám v celém systému, které jsou uživatelům vždy dostupné bez ohledu na to, jaká aplikace běží. 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 určit, která aplikace je aktuálně spuštěná. Obsahuje položky, které platí pro aplikaci jako celek, a ne daný dokument nebo proces, jako je ukončení aplikace.
  • Nabídka Soubor – položky používané k vytváření, otevření nebo ukládání dokumentů, se které vaše aplikace používá. Pokud vaše aplikace není založená na dokumentu, můžete tuto nabídku přejmenovat nebo odebrat.
  • Nabídka Upravit – obsahuje příkazy, jako jsou Vyjmutí,Kopírovánía Vložení, které slouží k úpravám nebo úpravám prvků v uživatelském rozhraní aplikace.
  • Nabídka Formát – pokud aplikace pracuje s textem, tato nabídka obsahuje příkazy pro úpravu formátování tohoto textu.
  • Nabídka Zobrazení – obsahuje příkazy, které ovlivňují způsob zobrazení (zobrazení) obsahu v uživatelském rozhraní aplikace.
  • Nabídky specifické pro aplikaci – všechny nabídky, které jsou specifické pro vaši aplikaci (například nabídka záložek pro webový prohlížeč). Měly by se zobrazovat mezi nabídkami Zobrazení a Okno na panelu.
  • Nabídka okna – obsahuje příkazy pro práci s okny ve vaší aplikaci a také seznam aktuálních 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 ta pravé.

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

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, který má typické položky, které by normálně měla aplikace pro macOS (jak je popsáno v části výše). Výchozí řádek nabídek vaší aplikace je definovaný v souboru Main.storyboard (společně se zbytkem uživatelského rozhraní vaší aplikace) v projektu v souboru Oblast řešení:

Výběr hlavního scénáře

Poklikejte na soubor Main.storyboard a otevřete ho pro úpravy v Interface Builder Xcode. Zobrazí se rozhraní editoru nabídek:

Úprava uživatelského rozhraní v Xcode se scénářem Hlavní tečka

Tady můžeme kliknout na položky, jako je například položka nabídky Otevřít v nabídce Soubor, a upravit nebo upravit její vlastnosti v nástroji Attributes Inspector:

Úprava atributů nabídky Při

K přidávání, úpravám a odstraňování nabídek a položek se dostaneme později v tomto článku. Teď chceme jenom zobrazit, které nabídky a položky nabídky 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).

Když například klikneme na inspektor připojení pro položku nabídky Otevřít, uvidíme, že je automaticky připojený k akci:

Zobrazení připojené akce

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

Zobrazení všech připojených akcí

Proč je to důležité? V další části se budeme podívat, jak tyto automaticky definované akce fungují s dalšími prvky uživatelského rozhraní Cocoa a automaticky povolují a zakují položky nabídky a také poskytují integrované funkce pro položky.

Později tyto integrované akce použijeme k povolení a zakázání položek v kódu a k poskytnutí vlastních funkcí, když jsou vybrány.

Funkce integrovaných nabídek

Pokud jste před přidáním jakýchkoli položek uživatelského rozhraní nebo kódu spouštěli nově vytvořenou aplikaci Xamarin.Mac, všimnete si, že některé položky jsou pro vás automaticky připojeny a povoleny (s automatickým integrovaným plně funkčním prostředím), jako je například položka Ukončit v nabídce Aplikace:

Povolená položka nabídky

I když jiné položky nabídky, například Vyjmout,Kopírovata Vložit, nejsou:

Zakázané položky nabídky

Zastavte aplikaci a poklikejte na soubor Main.storyboard v souboru Oblast řešení a otevřete ho pro úpravy v souboru Interface Builder. Dále přetáhněte zobrazení textu z knihovny do kontroleru zobrazení okna v Editoru rozhraní:

Výběr zobrazení textu z knihovny Výběrzobrazení textu z

V Editoru omezení připněme textové zobrazení k okrajům okna a nastavme ho tam, kde se zvětší a zmenší s oknem. Klikněte na všechny čtyři červené I-smyšlené výrazy v horní části editoru a klikněte na tlačítko Add 4 Constraints (Přidat 4 omezení):

Úprava omezení upravování

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

Položky nabídky jsou automaticky povolené nebo zakázané.

Všimněte si, že položky Vyjmout,Kopírovata Vložit jsou automaticky povolené a plně funkční, a to vše bez psaní jediného řádku kódu.

Co se tu děje? Zapamatovat si předdefinované akce, které jsou připojeny 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, má integrované připojení ke konkrétním akcím (například copy: ). Když jsou tedy přidány do okna, aktivní a vybrané, automaticky se povolí odpovídající položka nabídky nebo položky připojené k této akci. Pokud uživatel vybere tuto položku nabídky, volá a spustí se funkce integrované do elementu uživatelského rozhraní bez zásahu vývojáře.

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

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

  • Povolení automatické nabídky – Položka nabídky je povolená, pokud najde vhodný objekt, který reaguje na akci, ke které je položka připojená. Například výše uvedené zobrazení textu, které mělo integrovaný hook k copy: akci.
  • Vlastní akce avalidateMenuItem: – pro všechny položky nabídky, které jsou vázané na vlastní akci okna nebo kontroleru zobrazení, můžete přidat akci a ručně povolit nebo zakázat položky nabídky.
  • Povolení ruční nabídky – Ručně nastavíte vlastnost každé položky tak, aby se jednotlivé položky v nabídce NSMenuItem povolují nebo zakažují jednotlivě.

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

Důležité

Pokud se rozhodnete povolit ruční nabídku, žádná z položek nabídky, ani ty, které řídí třídy AppKitu, jako NSTextView je , se automaticky aktualizuje. 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 svázaná s vlastní akcí okna nebo kontroleru zobrazení,můžete přidat akci a ručně povolit nebo zakázat položky nabídky.

V následujícím příkladu se vlastnost použije k rozhodnutí o typu položky nabídky, kterou akce povolí nebo deaktivuje na základě stavu vybraného textu v TagvalidateMenuItem: objektu NSTextView . Vlastnost Tag byla nastavena v Interface Builder pro každou položku nabídky:

Nastavení vlastnosti Tag –

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 objektu není vybraný žádný text, jsou tyto dvě položky zalamovací nabídky zakázané (i když jsou připojeny k akcím v NSTextView kontroleru zobrazení):

Zobrazení zakázaných položek

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

Zobrazení povolených položek

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

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

Řekněme například, že chcete, aby uživatel mohl použít položku otevřít v nabídce soubor k výběru složky. Vzhledem k tomu, že chceme, aby to byla funkce pro celé aplikace, a ne omezení na okno předat nebo ovládací prvek uživatelského rozhraní, přidáme kód, který tomuto prvku zpracuje delegáta aplikace.

V oblast řešenídvakrát klikněte na soubor a otevřete ho pro úpravy:

Výběr delegáta aplikace

Do metody přidejte následující kód DidFinishLaunching :

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

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

Pojďme teď aplikaci spustit a otevřít nabídku soubor :

The File menuNabídka

Všimněte si, že položka otevřít nabídku je nyní povolena. Pokud ho vyberete, zobrazí se dialogové okno otevřít:

Otevření dialogového okna

Pokud klikneme na tlačítko otevřít , zobrazí se zpráva upozornění:

Příkladzprávy příkladem zprávy dialogového okna

Zde uvedený klíč [Export ("openDocument:")]NSMenu obsahuje informace o tom, že naše [Export ("openDocument:")] má metodu void OpenDialog (NSObject sender) , která reaguje na openDocument: akci. Pokud si pamatujete z výše uvedeného seznamu, je položka otevřít nabídku automaticky zapojená do této akce ve výchozím nastavení v Interface Builder:

Zobrazení připojených akcí, které

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

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

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

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

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

I když vaše aplikace nepoužívá NSDocuments , je stále NSDocumentController k dispozici nabídka pro NSDocuments nabídky odesláním NSUrl s umístěním souboru do NoteNewRecentDocumentURL metody SharedDocumentController .

Dále je nutné přepsat OpenFile metodu delegáta aplikace, aby se otevřel libovolný soubor, který uživatel vybral z nabídky OpenFile . Napří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;
    }
}

Vrátí true , zda lze soubor otevřít, jinak se vrátí false nebo se uživateli zobrazí předdefinované upozornění, že soubor nelze otevřít.

Vzhledem k tomu, že název souboru a cesta vracené z nabídky otevřít poslední může obsahovat mezeru, musíme před vytvořením tohoto znaku správně řídicí znak vytvořit nebo se zobrazí chyba. Máme to s následujícím kódem:

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

Nakonec vytvoříme NSUrl , který odkazuje 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);

Pokud si chcete všechno navzájem vyžádat, Podívejme se na příklad implementace 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
    }
}

Na základě požadavků vaší aplikace možná nebudete chtít, aby uživatel otevřel stejný soubor ve více než jednom okně současně. Pokud uživatel v naší ukázkové aplikaci zvolí soubor, který už je otevřený (buď z položek otevřít poslední nebo otevřít.. ), zobrazí se okno, které obsahuje soubor, do popředí.

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

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

Navrhli jsme naši ViewController třídu pro uložení cesty k souboru ve své Path Vlastnosti. V dalším kroku procházíme všemi aktuálně otevřenými okny v aplikaci. Pokud je soubor již v některém z oken otevřen, je umístěn do popředí všech ostatních oken pomocí:

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

Pokud se nenajde žádná shoda, otevře se nové okno s načteným souborem a soubor se zobrazí 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 akcemi vlastního okna

Stejně jako u vestavěných akcí , které přicházejí do standardních položek nabídky předem, můžete vytvořit nové, vlastní akce a roztáhnout je do položek nabídky v Interface Builder.

Nejdřív definujte vlastní akci na jednom z řadičů oken vaší aplikace. Například:

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

Pak dvakrát klikněte na soubor scénáře aplikace v oblast řešení a otevřete ho pro úpravy v Interface Builder Xcode. Vyberte první respondér v rámci scény aplikacea pak přepněte do inspektoru atributů:

Inspektor atributů

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

Přidání nové akce

Dejte mu stejný název jako vlastní akce, kterou jste vytvořili v řadiči vašeho okna:

Úprava názvu akce

Ovládací prvek – klikněte na položku nabídky a přetáhněte ji na první respondér v rámci scény aplikace. V rozevíracím seznamu vyberte novou akci, kterou jste právě vytvořili ( defineKeyword: v tomto příkladu):

Připojení akce, která

uložte změny do scénáře a vraťte se do Visual Studio pro Mac a synchronizujte změny. Spouštíte-li aplikaci, položka nabídky, na kterou jste propojenou vlastní akci, bude automaticky povolena/zakázána (na základě okna s akcí, která je otevřena) a výběrem položky nabídky se akce spustí:

Testování novéakce

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ídky, které konkrétní ovládací prvky uživatelského rozhraní budou automaticky aktivovat a reagovat na. Zjistili jsme také, jak do naší aplikace přidat kód, který bude také umožňovat a reagovat na tyto výchozí položky.

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

Dvojím kliknutím na soubor Main. scénáře v oblast řešení ho otevřete pro úpravy:

Dvojím kliknutím na soubor scénáře upravíte uživatelské rozhraní v Xcode.

Pro naši konkrétní aplikaci Xamarin. Mac nepoužíváme výchozí nabídku zobrazení , takže ji teď odebereme. V hierarchii rozhraní vyberte položku nabídky zobrazení , která je součástí hlavního panelu nabídek:

Výběr položky nabídky Zobrazit,

Stisknutím klávesy DELETE nebo BACKSPACE odstraňte nabídku. Dále nebudeme používat všechny položky v nabídce Formát a chceme přesunout položky, které využijete z dílčích nabídek. V hierarchii rozhraní vyberte následující položky nabídky:

Zvýraznění více položek, které

Přetáhněte položky v nadřazené nabídce z podnabídky, kde jsou aktuálně:

Přetahování položek nabídky do nadřazené nabídky

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

Položky v novém umístění

Nyní přetáhneme podnabídku text z nabídky Formát a umístíte ji na hlavní panel nabídek mezi formáty a nabídky okna :

Nabídka text

Pojďme se vrátit v nabídce Formát a odstranit položku podnabídky písma . Pak vyberte nabídku Formát a přejmenujte ji na "font":

Nabídka písmo

Nyní vytvoříme vlastní nabídku s předdefinovanými frázemi, které se automaticky připojí k textu v zobrazení text, když jsou vybrány. Do vyhledávacího pole v dolní části okna Kontrola knihovny zadejte v nabídce "nabídka". Díky tomu bude snazší najít a pracovat se všemi prvky uživatelského rozhraní nabídky:

Inspektorknihovny inspektor knihovny

Teď provedeme následující kroky, které vám pomůžou vytvořit naši nabídku:

  1. Přetáhněte položku nabídky z inspektoru knihovny na panel nabídek mezi textovou a okno nabídky:

    Výběr nové položky nabídky v knihovně

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

    Nastavení názvu nabídky

  3. Další přetáhněte nabídku z okna inspektor knihovny:

    Výběr nabídky z knihovny

  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":

    Úprava názvu nabídky

  5. Teď přejmenujte tři výchozí položky nabídky "adresa", "datum" a "pozdrav":

    Nabídkafráze

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

    Úprava názvu položky nabídky

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

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

Vytváření požadovaných akcí pro

Pojďme udělat toto:

  1. Control – přetáhněte z položky nabídky adresa do souboru AppDelegate. h .

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

    Výběr typu akce

  3. zadejte název "phraseAddress" a stisknutím tlačítka Připojení vytvořte novou akci:

    Konfigurace akce zadáním názvu

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

    Dokončené akce

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

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

Vytvoření výstupu

Vraťte se Visual Studio pro Mac a synchronizujte změny z Xcode. Dále upravte soubor ViewController.cs a navrchte 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 třídu a informuje delegáta aplikace, když okno získá ViewController nebo ztratí fokus. Teď upravte soubor AppDelegate.cs a udělejte, aby vypadal 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 udělali částečnou třídu, abychom mohli použít akce a výstupy, které jsme definovali AppDelegate v Interface Builder. Zveřejňujeme také , textEditor aby bylo možné sledovat, které okno je aktuálně fokus.

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

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 po výběru této možnosti přidají do textového zobrazení frázi:

Příklad spuštění aplikace Příklad

Teď, když máme základy práce s panelem nabídek aplikace dolů, se podívejme 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í Xcode Interface Builder můžou aplikace Xamarin.Mac potřebovat vytvořit, upravit nebo odebrat nabídku, podnabí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é se budou dynamicky vytvářet 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ání nabídek a položek

Když je tato třída definovaná, následující rutina bude parsovat kolekci objektů a rekurzivně sestaví nové nabídky a položky nabídky tak, že je připojí ke spodní části existující nabídky (vytvořené v Interface Builder), která byla LanguageFormatCommand 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ý objekt, který má prázdnou vlastnost, tato rutina vytvoří položku nabídky LanguageFormatCommand Oddělovač (tenká šedá čára) mezi Title oddíly nabídky: LanguageFormatCommand

menuItem = NSMenuItem.SeparatorItem;

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

menuItem = new NSMenuItem (command.Title);

Pokud objekt obsahuje podřízené objekty, vytvoří se podnabídka a rekurzivně se volá metoda , která LanguageFormatCommandLanguageFormatCommand tuto AssembleMenu nabídku sestaví:

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

Pro všechny nové položky nabídky, které nemají 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 objektů, je veškerý výše LanguageFormatCommand uvedený kód vytvořený:

// 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á funkci (s nabídkou Formát nastavenou jako základ), vytvoří se následující dynamické nabídky a AssembleMenu položky nabídky: AssembleMenu

Nové položky nabídky ve spuštěné aplikaciNové položky nabídky ve spuštěné

Odebrání nabídek a položek

Pokud potřebujete z uživatelského rozhraní aplikace odebrat jakoukoli nabídku nebo položku nabídky, můžete použít metodu třídy jednoduše tak, že jí dáte index položky, který se má odebrat od RemoveItemAtNSMenu nuly.

Pokud například chcete 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 souboru Interface Builder Xcode a v aplikaci se odstraní, takže se dynamicky nepřichová.

Kontextové nabídky

Místní nabídky se zobrazí, když uživatel klikne pravým tlačítkem nebo klikne na položku v okně. Ve výchozím nastavení už několik prvků uživatelského rozhraní integrovaných do macOS má připojené kontextové nabídky (například textové zobrazení). Mohou však nastane čas, kdy chceme 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 do našeho návrhu okno okna, nastavit jeho třídu na "NSPanel" v nástroji Identity Inspector,přidat novou položku Asistenta do nabídky Okno a připojit ji k novému okně pomocí příkazu Show Se za použití příkazu Show Se zak:

Nastavení základního typu v souboru scénáře Hlavní tečka

Pustíme se do následujících akcí:

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

    Úprava hodnoty popisku Úprava

  2. Pak přetáhněte nabídku z inspektoru knihovny na kontroler zobrazení v hierarchii zobrazení a přejmenujte tři výchozí položky nabídky Document, Text a Font:

    Požadované položky nabídky

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

    Přetažením vytvořte segální

  4. V automaticky otevíraného dialogovém okně vyberte Nabídka:

    Nastavení segového typu výběrem nabídky z výstupu v místní nabídce Popisek.

  5. V kontroleru identitnastavte třídu kontroleru zobrazení na PanelViewController:

    Nastavení třídy se class

  6. Přepněte zpět Visual Studio pro Mac synchronizaci a pak se vraťte do Interface Builder.

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

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

    Konfigurace akce s názvem propertyDocument

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

    Opakující se akce u zbývajících položek nabídky

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

    Konfigurace výstupu

  11. Uložte změny a vraťte se do Visual Studio pro Mac 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 na popisek vlastnosti na panelu, uvidíme naši vlastní kontextovou nabídku. Pokud v nabídce vybereme a item, hodnota popisku se změní:

Místní nabídka se spuštěnou

Teď se podívejme 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é uživateli poskytují interakci nebo zpětnou vazbu, například nabídku nebo obrázek, který odráží stav aplikace. Nabídka stavového řádku aplikace je povolená a aktivní i v případě, že aplikace běží na pozadí. Stavový řádek pro celou systém se nachází na pravé straně řádku nabídek aplikace a je jediným stavový řádek aktuálně dostupný v systému macOS.

Pojďme upravit soubor AppDelegate.cs a metodu upravit tak, aby vypadala 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 ke stavovém řádku 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 aplikaci spustíme, zobrazí se nová položka stavového řádku. Výběrem položky z nabídky změníte text v textovém zobrazení:

Nabídka stavového řádku se spuštěnou

Teď se podíváme na vytvoření vlastních položek nabídky ukotvení.

Vlastní nabídky ukotvení

Nabídka Docku se zobrazí pro aplikaci pro Mac, když uživatel klikne pravým tlačítkem nebo klikne na ikonu aplikace v Docku:

Vlastní nabídka ukotvit

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

  1. V Visual Studio pro Mac klikněte pravým tlačítkem na projekt aplikace a vyberte Přidatnový soubor... V dialogovém okně nový soubor vyberte Xamarin.Mac Empty Interface Definition (Prázdná definice rozhraní Xamarin.Mac),jako Název použijte DockMenu a kliknutím na tlačítko New (Nový) vytvořte nový soubor DockMenu.xib:

    Přidání prázdné definice rozhraní Přidáníprázdné definice

  2. V Oblast ř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: Address (Adresa),Date (Datum),Greeting(Pozdrav) a Signature (Podpis).

    Rozložení uživatelského rozhraní

  3. Teď připojíme nové položky nabídky k našim existujícím akcím, které jsme vytvořili pro naši vlastní nabídku výše v části Přidávání, úpravy a odstraňování nabídek. Přepněte do inspektoru připojení a v hierarchii rozhraní vyberte First Responder(První respondér). Posuňte se dolů a najděte phraseAddress: akci. Přetáhněte čáru z kruhu u této akce do položky nabídky Adresa:

    Přetažení řádku na položku nabídky Adresa

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

    Opakuje se u ostatních položek nabídky, které je připojují k jejich odpovídajícím akcím.

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

    Přetažení vodiče nahoru na zásuvku

  6. Uložte změny a přepněte zpět na Visual Studio pro Mac synchronizaci s Xcode.

  7. Poklikejte na soubor Info.plist a otevřete ho pro úpravy:

    Úprava souboru Info.plist

  8. V dolní části obrazovky klikněte na kartu Zdroj:

    Výběr zobrazení Zdroj

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

    Přidání položky DockMenu Přidání

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

Příklad spuštění nabídky Docku Příklad

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

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ých si můžete vybrat, když na něj uživatel klikne. Rozevírací seznam je typ překryvového tlačítka, které se obvykle používá pro výběr příkazů specifických pro kontext aktuální úlohy. Obojí se může zobrazit kdekoli v okně.

Pojďme vytvořit vlastní automaticky otevírané tlačítko pro naši aplikaci následujícím způsobem:

  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:

    Přidání překryvného tlačítka

  2. Přidejte novou položku nabídky a nastavte názvy položek v místní nabídce na: Adresa,Datum,Pozdrava Podpis.

    Konfigurace položek nabídky

  3. Teď připojíme nové položky nabídky ke stávajícím akcím, které jsme vytvořili pro naši vlastní nabídku výše v části Přidávání, úpravy a odstraňování nabídek. Přepněte do inspektoru připojení a v hierarchii rozhraní vyberte First Responder(První respondér). Posuňte se dolů a najděte phraseAddress: akci. Přetáhněte čáru z kruhu u této akce do položky nabídky Adresa:

    Přetažením akce nahoru

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

    Všechny požadované akce

  5. Uložte změny a přepněte zpět na Visual Studio pro Mac synchronizaci s Xcode.

Když teď spustíme aplikaci a vybereme položku z automaticky otevíraného okna, text v našem textovém zobrazení se změní:

Příklad automaticky otevíraného okna se spuštěnou

Rozevírací seznamy můžete vytvářet a pracovat úplně stejně jako s automaticky otevíranou tlačítky. Místo připojení k existující akci byste mohli vytvořit vlastní akce stejně, jako jsme to udělali u místní nabídky v části Kontextové nabídky.

Souhrn

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