Dialogy v Xamarin.Mac

Při práci s jazykem C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným dialogům a modálnímu Windows, ve kterých vývojář pracuje Objective-C a Xcode . Vzhledem k tomu, že se Xamarin.Mac integruje přímo s Xcode, můžete pomocí Tvůrce rozhraní Xcode vytvořit a udržovat modální windows (nebo je volitelně vytvořit přímo v kódu jazyka C#).

Dialogové okno se zobrazí v reakci na akci uživatele a obvykle poskytuje způsoby, jak můžou uživatelé akci dokončit. Dialogové okno vyžaduje odpověď od uživatele, než ho lze zavřít.

Systém Windows lze použít v bezmodálním stavu (například textový editor, který může mít najednou otevřený více dokumentů) nebo modální (například dialogové okno exportu, které musí být zamítnuto před pokračováním aplikace).

An open dialog box

V tomto článku se budeme zabývat základy práce s dialogy a modálními Windows 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.

Možná se také budete chtít podívat na oddíly v dokumentu Interní dokumenty Xamarin.Mac pro zveřejnění tříd a metodObjective-Cjazyka C#. Vysvětluje také, které Register příkazy a Export které se používají k připojení tříd jazyka C# k Objective-C objektům a prvkům uživatelského rozhraní.

Úvod do dialogových oken

Dialogové okno se zobrazí v reakci na akci uživatele (například uložení souboru) a poskytuje uživatelům způsob, jak tuto akci dokončit. Dialogové okno vyžaduje odpověď od uživatele, než ho lze zavřít.

Podle Společnosti Apple existují tři způsoby prezentace dialogového okna:

  • Modální dokument – Modální dialogové okno dokumentu brání uživateli v provádění čehokoli jiného v daném dokumentu, dokud ho nespustíte.
  • Modální aplikace – Dialogové okno Modální aplikace brání uživateli v interakci s aplikací, dokud se nespustí.
  • Modeless A Modeless Dialog umožňuje uživatelům měnit nastavení v dialogovém okně a přitom pracovat s oknem dokumentu.

Libovolný standard NSWindow lze použít jako přizpůsobený dialog tak, že ho zobrazíte modálně:

An example modal window

Modální listy dokumentu

List je modální dialogové okno připojené k danému okně dokumentu, které uživatelům brání v interakci s oknem, dokud dialogové okno nezavřou. List je připojen k oknem, ze kterého se objeví, a současně lze otevřít pouze jeden list pro okno.

An example modal sheet

Předvolby windows

Okno Předvolby je bezmodální dialogové okno, které obsahuje nastavení aplikace, které uživatel mění zřídka. Okna předvoleb často obsahují panel nástrojů, který uživateli umožňuje přepínat mezi různými skupinami nastavení:

An example preference window

Otevřít dialogové okno

Dialogové okno Otevřít poskytuje uživatelům konzistentní způsob, jak najít a otevřít položku v aplikaci:

A open dialog box

macOS poskytuje standardní dialogová okna Pro tisk a vzhled stránky, která může aplikace zobrazit, aby uživatelé mohli mít konzistentní možnosti tisku v každé aplikaci, kterou používají.

Dialogové okno Tisk se dá zobrazit jako volné plovoucí dialogové okno:

A print dialog box

Nebo ho můžete zobrazit jako list:

A print sheet

Dialogové okno Vzhled stránky se dá zobrazit jako volné plovoucí dialogové okno:

A page setup dialog

Nebo ho můžete zobrazit jako list:

A page setup sheet

Uložit dialogy

Dialogové okno Uložit umožňuje uživatelům konzistentní způsob, jak uložit položku v aplikaci. Dialogové okno Uložit má dva stavy: Minimum (označované také jako Sbalené):

A save dialog

A rozbalený stav:

An expanded save dialog

Dialogové okno Minimální uložení lze také zobrazit jako list:

A minimal save sheet

Jak je možné v dialogovém okně Rozbalené uložení:

An expanded save sheet

Další informace najdete v části Dialogy v Pokynech pro lidské rozhraní OS X společnosti Apple .

Přidání modálního okna do projektu

Kromě hlavního okna dokumentu může aplikace Xamarin.Mac potřebovat uživateli zobrazit jiné typy oken, jako jsou předvolby nebo panely inspektoru.

Pokud chcete přidat nové okno, postupujte takto:

  1. V Průzkumník řešení otevřete Main.storyboard soubor pro úpravy v Tvůrci rozhraní Xcode.

  2. Přetáhněte nový kontroler zobrazení na návrhovou plochu:

    Selecting a View Controller from the Library

  3. V nástroji Identity Inspector zadejte CustomDialogController název třídy:

    Setting the class name to CustomDialogController.

  4. Přepněte zpátky na Visual Studio pro Mac, povolte synchronizaci s Xcode a vytvořte CustomDialogController.h soubor.

  5. Vraťte se do Xcode a navrhněte své rozhraní:

    Designing the UI in Xcode

  6. Vytvořte modální segue z hlavního okna aplikace do nového kontroleru zobrazení přetažením z prvku uživatelského rozhraní, který otevře dialogové okno do okna dialogového okna. Přiřaďte identifikátorModalSegue:

    A modal segue

  7. Připojení všech akcí a výstupů:

    Configuring an Action

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

Udělejte soubor CustomDialogController.cs takto:

using System;
using Foundation;
using AppKit;

namespace MacDialog
{
    public partial class CustomDialogController : NSViewController
    {
        #region Private Variables
        private string _dialogTitle = "Title";
        private string _dialogDescription = "Description";
        private NSViewController _presentor;
        #endregion

        #region Computed Properties
        public string DialogTitle {
            get { return _dialogTitle; }
            set { _dialogTitle = value; }
        }

        public string DialogDescription {
            get { return _dialogDescription; }
            set { _dialogDescription = value; }
        }

        public NSViewController Presentor {
            get { return _presentor; }
            set { _presentor = value; }
        }
        #endregion

        #region Constructors
        public CustomDialogController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void ViewWillAppear ()
        {
            base.ViewWillAppear ();

            // Set initial title and description
            Title.StringValue = DialogTitle;
            Description.StringValue = DialogDescription;
        }
        #endregion

        #region Private Methods
        private void CloseDialog() {
            Presentor.DismissViewController (this);
        }
        #endregion

        #region Custom Actions
        partial void AcceptDialog (Foundation.NSObject sender) {
            RaiseDialogAccepted();
            CloseDialog();
        }

        partial void CancelDialog (Foundation.NSObject sender) {
            RaiseDialogCanceled();
            CloseDialog();
        }
        #endregion

        #region Events
        public EventHandler DialogAccepted;

        internal void RaiseDialogAccepted() {
            if (this.DialogAccepted != null)
                this.DialogAccepted (this, EventArgs.Empty);
        }

        public EventHandler DialogCanceled;

        internal void RaiseDialogCanceled() {
            if (this.DialogCanceled != null)
                this.DialogCanceled (this, EventArgs.Empty);
        }
        #endregion
    }
}

Tento kód zveřejňuje několik vlastností pro nastavení názvu a popisu dialogového okna a několika událostí, které reagují na zrušené nebo přijaté dialogové okno.

Dále upravte ViewController.cs soubor, přepište metodu PrepareForSegue a udělejte ji takto:

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on the segue name
    switch (segue.Identifier) {
    case "ModalSegue":
        var dialog = segue.DestinationController as CustomDialogController;
        dialog.DialogTitle = "MacDialog";
        dialog.DialogDescription = "This is a sample dialog.";
        dialog.DialogAccepted += (s, e) => {
            Console.WriteLine ("Dialog accepted");
            DismissViewController (dialog);
        };
        dialog.Presentor = this;
        break;
    }
}

Tento kód inicializujegue, který jsme definovali v Tvůrci rozhraní Xcode, do našeho dialogového okna a nastaví název a popis. Zpracovává také volbu, která uživatel provede v dialogovém okně.

Aplikaci můžeme spustit a zobrazit vlastní dialogové okno:

An example dialog

Další informace o používání oken v aplikaci Xamarin.Mac najdete v naší dokumentaci k práci s Windows .

Vytvoření vlastního listu

List je modální dialogové okno připojené k danému okně dokumentu, které uživatelům brání v interakci s oknem, dokud dialogové okno nezavřou. List je připojen k oknem, ze kterého se objeví, a současně lze otevřít pouze jeden list pro okno.

Pokud chcete vytvořit vlastní list v Xamarin.Mac, udělejme toto:

  1. V Průzkumník řešení otevřete Main.storyboard soubor pro úpravy v Tvůrci rozhraní Xcode.

  2. Přetáhněte nový kontroler zobrazení na návrhovou plochu:

    Selecting a View Controller from the Library

  3. Navrhněte uživatelské rozhraní:

    The UI design

  4. Vytvořte list segue z hlavního okna na nový kontroler zobrazení:

    Selecting the Sheet segue type

  5. V nástroji Identity Inspector pojmenujte tříduSheetViewController kontroleru zobrazení:

    Setting the class name to SheetViewController.

  6. Definujte všechny potřebné výstupy a akce:

    Defining the required Outlets and Actions

  7. Uložte změny a vraťte se do Visual Studio pro Mac k synchronizaci.

Potom upravte SheetViewController.cs soubor a udělejte ho takto:

using System;
using Foundation;
using AppKit;

namespace MacDialog
{
    public partial class SheetViewController : NSViewController
    {
        #region Private Variables
        private string _userName = "";
        private string _password = "";
        private NSViewController _presentor;
        #endregion

        #region Computed Properties
        public string UserName {
            get { return _userName; }
            set { _userName = value; }
        }

        public string Password {
            get { return _password;}
            set { _password = value;}
        }

        public NSViewController Presentor {
            get { return _presentor; }
            set { _presentor = value; }
        }
        #endregion

        #region Constructors
        public SheetViewController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void ViewWillAppear ()
        {
            base.ViewWillAppear ();

            // Set initial values
            NameField.StringValue = UserName;
            PasswordField.StringValue = Password;

            // Wireup events
            NameField.Changed += (sender, e) => {
                UserName = NameField.StringValue;
            };
            PasswordField.Changed += (sender, e) => {
                Password = PasswordField.StringValue;
            };
        }
        #endregion

        #region Private Methods
        private void CloseSheet() {
            Presentor.DismissViewController (this);
        }
        #endregion

        #region Custom Actions
        partial void AcceptSheet (Foundation.NSObject sender) {
            RaiseSheetAccepted();
            CloseSheet();
        }

        partial void CancelSheet (Foundation.NSObject sender) {
            RaiseSheetCanceled();
            CloseSheet();
        }
        #endregion

        #region Events
        public EventHandler SheetAccepted;

        internal void RaiseSheetAccepted() {
            if (this.SheetAccepted != null)
                this.SheetAccepted (this, EventArgs.Empty);
        }

        public EventHandler SheetCanceled;

        internal void RaiseSheetCanceled() {
            if (this.SheetCanceled != null)
                this.SheetCanceled (this, EventArgs.Empty);
        }
        #endregion
    }
}

Dále upravte ViewController.cs soubor, upravte metodu PrepareForSegue a udělejte ji takto:

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on the segue name
    switch (segue.Identifier) {
    case "ModalSegue":
        var dialog = segue.DestinationController as CustomDialogController;
        dialog.DialogTitle = "MacDialog";
        dialog.DialogDescription = "This is a sample dialog.";
        dialog.DialogAccepted += (s, e) => {
            Console.WriteLine ("Dialog accepted");
            DismissViewController (dialog);
        };
        dialog.Presentor = this;
        break;
    case "SheetSegue":
        var sheet = segue.DestinationController as SheetViewController;
        sheet.SheetAccepted += (s, e) => {
            Console.WriteLine ("User Name: {0} Password: {1}", sheet.UserName, sheet.Password);
        };
        sheet.Presentor = this;
        break;
    }
}

Pokud spustíme naši aplikaci a otevřeme list, připojí se k oknem:

An example sheet

Dialogové okno Vytvoření předvoleb

Před rozložením zobrazení předvoleb v Tvůrci rozhraní budeme muset přidat vlastní typgue pro zpracování přepínání předvoleb. Přidejte do projektu novou třídu a zavolejte ji ReplaceViewSeque. Upravte třídu a udělejte ji takto:

using System;
using AppKit;
using Foundation;

namespace MacWindows
{
    [Register("ReplaceViewSeque")]
    public class ReplaceViewSeque : NSStoryboardSegue
    {
        #region Constructors
        public ReplaceViewSeque() {

        }

        public ReplaceViewSeque (string identifier, NSObject sourceController, NSObject destinationController) : base(identifier,sourceController,destinationController) {

        }

        public ReplaceViewSeque (IntPtr handle) : base(handle) {
        }

        public ReplaceViewSeque (NSObjectFlag x) : base(x) {
        }
        #endregion

        #region Override Methods
        public override void Perform ()
        {
            // Cast the source and destination controllers
            var source = SourceController as NSViewController;
            var destination = DestinationController as NSViewController;

            // Is there a source?
            if (source == null) {
                // No, get the current key window
                var window = NSApplication.SharedApplication.KeyWindow;

                // Swap the controllers
                window.ContentViewController = destination;

                // Release memory
                window.ContentViewController?.RemoveFromParentViewController ();
            } else {
                // Swap the controllers
                source.View.Window.ContentViewController = destination;

                // Release memory
                source.RemoveFromParentViewController ();
            }
        
        }
        #endregion

    }

}

S vlastní gue vytvořený, můžeme přidat nové okno v Xcode Interface Builder pro zpracování našich předvoleb.

Pokud chcete přidat nové okno, postupujte takto:

  1. V Průzkumník řešení otevřete Main.storyboard soubor pro úpravy v Tvůrci rozhraní Xcode.

  2. Přetáhněte nový ovladač okna na návrhovou plochu:

    Select a Window Controller from the Library

  3. Uspořádejte okno poblíž návrháře řádku nabídek:

    Adding the new Window

  4. Vytvořte kopie připojeného kontroleru zobrazení, protože v zobrazení předvoleb budou karty:

    Adding the required View Controllers

  5. Přetáhněte nový kontroler panelu nástrojů z knihovny:

    Select a Toolbar Controller from the Library

  6. A umístěte ho na okno na návrhové ploše:

    Adding a new Toolbar Controller

  7. Rozložení návrhu panelu nástrojů:

    Layout the toolbar

  8. Control-Click and drag from each Toolbar Button to the Views you created above. Vyberte vlastní typgue:

    Setting a Custom segue type.

  9. Vyberte nový Segue a nastavte třídu na ReplaceViewSegue:

    Setting the segue class

  10. V Návrháři řádku nabídek na návrhové ploše v nabídce aplikace vyberte Předvolby..., control-click and drag to the Preferences Window to create a Show segue:

    Setting the segue type by dragging Preferences to the Preferences Window.

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

Pokud kód spustíme a v nabídce Aplikace vybereme předvolby... zobrazí se okno:

An example preferences window displaying the word Profile.

Další informace o práci s Windows a panely nástrojů najdete v naší dokumentaci k windows a panelům nástrojů.

Ukládání a načítání předvoleb

Když uživatel v typické aplikaci pro macOS provede změny v některé z uživatelských předvoleb aplikace, uloží se tyto změny automaticky. Nejjednodušší způsob, jak to vyřešit v aplikaci Xamarin.Mac, je vytvořit jednu třídu pro správu všech předvoleb uživatele a sdílet ji v celém systému.

Nejprve přidejte do projektu novou AppPreferences třídu a dědí z NSObject. Předvolby budou navrženy tak, aby používaly datové vazby a kódování klíč-hodnota, díky čemuž bude proces vytváření a údržby upřednostňovaných formulářů mnohem jednodušší. Vzhledem k tomu, že předvolby se skládají z malého množství jednoduchých datových typů, použijte předdefinované NSUserDefaults k ukládání a načítání hodnot.

AppPreferences.cs Upravte soubor a udělejte ho takto:

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    [Register("AppPreferences")]
    public class AppPreferences : NSObject
    {
        #region Computed Properties
        [Export("DefaultLanguage")]
        public int DefaultLanguage {
            get { 
                var value = LoadInt ("DefaultLanguage", 0);
                return value; 
            }
            set {
                WillChangeValue ("DefaultLanguage");
                SaveInt ("DefaultLanguage", value, true);
                DidChangeValue ("DefaultLanguage");
            }
        }

        [Export("SmartLinks")]
        public bool SmartLinks {
            get { return LoadBool ("SmartLinks", true); }
            set {
                WillChangeValue ("SmartLinks");
                SaveBool ("SmartLinks", value, true);
                DidChangeValue ("SmartLinks");
            }
        }

        // Define any other required user preferences in the same fashion
        ...

        [Export("EditorBackgroundColor")]
        public NSColor EditorBackgroundColor {
            get { return LoadColor("EditorBackgroundColor", NSColor.White); }
            set {
                WillChangeValue ("EditorBackgroundColor");
                SaveColor ("EditorBackgroundColor", value, true);
                DidChangeValue ("EditorBackgroundColor");
            }
        }
        #endregion

        #region Constructors
        public AppPreferences ()
        {
        }
        #endregion

        #region Public Methods
        public int LoadInt(string key, int defaultValue) {
            // Attempt to read int
            var number = NSUserDefaults.StandardUserDefaults.IntForKey(key);

            // Take action based on value
            if (number == null) {
                return defaultValue;
            } else {
                return (int)number;
            }
        }
            
        public void SaveInt(string key, int value, bool sync) {
            NSUserDefaults.StandardUserDefaults.SetInt(value, key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }

        public bool LoadBool(string key, bool defaultValue) {
            // Attempt to read int
            var value = NSUserDefaults.StandardUserDefaults.BoolForKey(key);

            // Take action based on value
            if (value == null) {
                return defaultValue;
            } else {
                return value;
            }
        }

        public void SaveBool(string key, bool value, bool sync) {
            NSUserDefaults.StandardUserDefaults.SetBool(value, key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }

        public string NSColorToHexString(NSColor color, bool withAlpha) {
            //Break color into pieces
            nfloat red=0, green=0, blue=0, alpha=0;
            color.GetRgba (out red, out green, out blue, out alpha);

            // Adjust to byte
            alpha *= 255;
            red *= 255;
            green *= 255;
            blue *= 255;

            //With the alpha value?
            if (withAlpha) {
                return String.Format ("#{0:X2}{1:X2}{2:X2}{3:X2}", (int)alpha, (int)red, (int)green, (int)blue);
            } else {
                return String.Format ("#{0:X2}{1:X2}{2:X2}", (int)red, (int)green, (int)blue);
            }
        }

        public NSColor NSColorFromHexString (string hexValue)
        {
            var colorString = hexValue.Replace ("#", "");
            float red, green, blue, alpha;

            // Convert color based on length
            switch (colorString.Length) {
            case 3 : // #RGB
                red = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(0, 1)), 16) / 255f;
                green = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(1, 1)), 16) / 255f;
                blue = Convert.ToInt32(string.Format("{0}{0}", colorString.Substring(2, 1)), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, 1.0f);
            case 6 : // #RRGGBB
                red = Convert.ToInt32(colorString.Substring(0, 2), 16) / 255f;
                green = Convert.ToInt32(colorString.Substring(2, 2), 16) / 255f;
                blue = Convert.ToInt32(colorString.Substring(4, 2), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, 1.0f);
            case 8 : // #AARRGGBB
                alpha = Convert.ToInt32(colorString.Substring(0, 2), 16) / 255f;
                red = Convert.ToInt32(colorString.Substring(2, 2), 16) / 255f;
                green = Convert.ToInt32(colorString.Substring(4, 2), 16) / 255f;
                blue = Convert.ToInt32(colorString.Substring(6, 2), 16) / 255f;
                return NSColor.FromRgba(red, green, blue, alpha);
            default :
                throw new ArgumentOutOfRangeException(string.Format("Invalid color value '{0}'. It should be a hex value of the form #RBG, #RRGGBB or #AARRGGBB", hexValue));
            }
        }

        public NSColor LoadColor(string key, NSColor defaultValue) {

            // Attempt to read color
            var hex = NSUserDefaults.StandardUserDefaults.StringForKey(key);

            // Take action based on value
            if (hex == null) {
                return defaultValue;
            } else {
                return NSColorFromHexString (hex);
            }
        }

        public void SaveColor(string key, NSColor color, bool sync) {
            // Save to default
            NSUserDefaults.StandardUserDefaults.SetString(NSColorToHexString(color,true), key);
            if (sync) NSUserDefaults.StandardUserDefaults.Synchronize ();
        }
        #endregion
    }
}

Tato třída obsahuje několik pomocných rutin, jako SaveIntje , , LoadIntSaveColor, LoadColor, atd. pro usnadnění práceNSUserDefaults. Vzhledem k tomu, že NSUserDefaults nemá integrovaný způsob NSColorszpracování , NSColorToHexString a NSColorFromHexString metody se používají k převodu barev na webové šestnáctkové řetězce (#RRGGBBAA kde AA je alfa průhlednost), které lze snadno uložit a načíst.

AppDelegate.cs V souboru vytvořte instanci objektu AppPreferences, který bude použit pro celou aplikaci:

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

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

        public AppPreferences Preferences { get; set; } = new AppPreferences();
        #endregion

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion
        
        ...

Předvolby zapojení do zobrazení předvoleb

Dále připojte třídu Preference k prvkům uživatelského rozhraní v okně předvoleb a zobrazeních vytvořených výše. V Tvůrci rozhraní vyberte kontroler zobrazení předvoleb a přepněte na Kontrolu identit a vytvořte pro kontroler vlastní třídu:

The Identity Inspector

Přepněte zpět na Visual Studio pro Mac, aby se změny synchronizovaly, a otevřete nově vytvořenou třídu pro úpravy. Udělejte třídu takto:

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    public partial class EditorPrefsController : NSViewController
    {
        #region Application Access
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Computed Properties
        [Export("Preferences")]
        public AppPreferences Preferences {
            get { return App.Preferences; }
        }
        #endregion

        #region Constructors
        public EditorPrefsController (IntPtr handle) : base (handle)
        {
        }
        #endregion
    }
}

Všimněte si, že tato třída udělala dvě věci: Nejprve existuje pomocná App vlastnost, která usnadňuje přístup k AppDelegate . Za druhé vlastnost Preferences zveřejňuje globální třídu AppPreferences pro datovou vazbu s libovolnými ovládacími prvky uživatelského rozhraní umístěnými v tomto zobrazení.

Potom poklikejte na soubor Storyboard a znovu ho otevřete v Tvůrci rozhraní (a podívejte se na změny, které jste právě provedli výše). Přetáhněte všechny ovládací prvky uživatelského rozhraní potřebné k sestavení rozhraní předvoleb do zobrazení. U každého ovládacího prvku přepněte na kontrolu vazeb a vytvořte vazbu na jednotlivé vlastnosti třídy AppPreference :

The Binding Inspector

Opakujte výše uvedené kroky pro všechny požadované panely (kontrolery zobrazení) a vlastnosti předvoleb.

Použití změn předvoleb u všech otevřených oken

Jak je uvedeno výše, v typické aplikaci pro macOS platí, že když uživatel provede změny v některé z uživatelských předvoleb aplikace, uloží se tyto změny automaticky a použijí se na všechna okna, která uživatel mohl otevřít v aplikaci.

Pečlivé plánování a návrh předvoleb a oken vaší aplikace umožní, aby se tento proces pro koncového uživatele hladce a transparentně s minimálním množstvím práce na kódování.

Pro každé okno, které bude využívat Předvolby aplikace, přidejte následující pomocnou vlastnost do kontroleru zobrazení obsahu, aby byl přístup k naší appDelegate jednodušší:

#region Application Access
public static AppDelegate App {
    get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion

Dále přidejte třídu pro konfiguraci obsahu nebo chování na základě předvoleb uživatele:

public void ConfigureEditor() {

    // General Preferences
    TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
    TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
    ...

}

Při prvním otevření okna je potřeba volat metodu konfigurace, abyste měli jistotu, že odpovídá předvolbám uživatele:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Configure editor from user preferences
    ConfigureEditor ();
    ...
}

Dále upravte AppDelegate.cs soubor a přidejte následující metodu, aby se všechny změny předvoleb použily ve všech otevřených oknech:

public void UpdateWindowPreferences() {

    // Process all open windows
    for(int n=0; n<NSApplication.SharedApplication.Windows.Length; ++n) {
        var content = NSApplication.SharedApplication.Windows[n].ContentViewController as ViewController;
        if (content != null ) {
            // Reformat all text
            content.ConfigureEditor ();
        }
    }

}

V dalším kroku přidejte PreferenceWindowDelegate do projektu třídu a udělejte ji takto:

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

namespace SourceWriter
{
    public class PreferenceWindowDelegate : NSWindowDelegate
    {
        #region Application Access
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Computed Properties
        public NSWindow Window { get; set;}
        #endregion

        #region constructors
        public PreferenceWindowDelegate (NSWindow window)
        {
            // Initialize
            this.Window = window;

        }
        #endregion

        #region Override Methods
        public override bool WindowShouldClose (Foundation.NSObject sender)
        {
            
            // Apply any changes to open windows
            App.UpdateWindowPreferences();

            return true;
        }
        #endregion
    }
}

To způsobí, že se všechny změny předvoleb odešlou do všech otevřených oken, když se okno předvoleb zavře.

Nakonec upravte řadič okna předvoleb a přidejte delegáta vytvořeného výše:

using System;
using Foundation;
using AppKit;

namespace SourceWriter
{
    public partial class PreferenceWindowController : NSWindowController
    {
        #region Constructors
        public PreferenceWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Initialize
            Window.Delegate = new PreferenceWindowDelegate(Window);
            Toolbar.SelectedItemIdentifier = "General";
        }
        #endregion
    }
}

Pokud uživatel upraví předvolby aplikace a zavře okno předvoleb, změny se použijí pro všechny otevřené Windows:

An example Preferences Window, displayed with several other open windows.

Dialogové okno Otevřít

Dialogové okno Otevřít poskytuje uživatelům konzistentní způsob, jak najít a otevřít položku v aplikaci. Chcete-li zobrazit dialogové okno Otevřít v aplikaci Xamarin.Mac, použijte následující kód:

var dlg = NSOpenPanel.OpenPanel;
dlg.CanChooseFiles = true;
dlg.CanChooseDirectories = false;
dlg.AllowedFileTypes = new string[] { "txt", "html", "md", "css" };

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

    if (url != null) {
        var path = url.Path;

        // Create a new window to hold the text
        var newWindowController = new MainWindowController ();
        newWindowController.Window.MakeKeyAndOrderFront (this);

        // Load the text into the window
        var window = newWindowController.Window as MainWindow;
        window.Text = File.ReadAllText(path);
        window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
        window.RepresentedUrl = url;

    }
}

Ve výše uvedeném kódu otevíráme nové okno dokumentu pro zobrazení obsahu souboru. Tento kód budete muset nahradit funkcemi, které vyžaduje vaše aplikace.

Při práci s NSOpenPanelaplikací jsou k dispozici následující vlastnosti:

  • CanChooseFiles – Pokud true uživatel může vybrat soubory.
  • CanChooseDirectories – pokud true uživatel může vybrat adresáře.
  • AllowsMultipleSelection – Pokud true uživatel může vybrat více souborů najednou.
  • ResolveAliases – Pokud true vyberete a alias, přeloží ho na cestu k původnímu souboru.
  • AllowedFileTypes – je pole řetězců typů souborů, které uživatel může vybrat jako příponu nebo UTI. Výchozí hodnota je null, která umožňuje otevření libovolného souboru.

Metoda RunModal () zobrazí dialogové okno Otevřít a umožní uživateli vybrat soubory nebo adresáře (jak jsou zadány vlastnostmi) a vrátí 1 se, pokud uživatel klikne na tlačítko Otevřít .

Dialogové okno Otevřít vrátí vybrané soubory nebo adresáře uživatele jako pole adres URL ve URL vlastnosti.

Pokud program spustíme a v nabídce Soubor vybereme položku Otevřít... zobrazí se následující položky:

An open dialog box

Dialogy Nastavení tisku a stránky

macOS poskytuje standardní dialogová okna Pro tisk a vzhled stránky, která může aplikace zobrazit, aby uživatelé mohli mít konzistentní možnosti tisku v každé aplikaci, kterou používají.

Následující kód zobrazí standardní dialogové okno tisku:

public bool ShowPrintAsSheet { get; set;} = true;
...

[Export ("showPrinter:")]
void ShowDocument (NSObject sender) {
    var dlg = new NSPrintPanel();

    // Display the print dialog as dialog box
    if (ShowPrintAsSheet) {
        dlg.BeginSheet(new NSPrintInfo(),this,this,null,new IntPtr());
    } else {
        if (dlg.RunModalWithPrintInfo(new NSPrintInfo()) == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to print the document here...",
                MessageText = "Print Document",
            };
            alert.RunModal ();
        }
    }
}

Pokud vlastnost nastavíme ShowPrintAsSheet na false, spusťte aplikaci a zobrazte dialogové okno tisku, zobrazí se následující:

A print dialog box

Pokud vlastnost nastavíte ShowPrintAsSheet na true, spusťte aplikaci a zobrazte dialogové okno tisku, zobrazí se následující:

A print sheet

Následující kód zobrazí dialogové okno Rozložení stránky:

[Export ("showLayout:")]
void ShowLayout (NSObject sender) {
    var dlg = new NSPageLayout();

    // Display the print dialog as dialog box
    if (ShowPrintAsSheet) {
        dlg.BeginSheet (new NSPrintInfo (), this);
    } else {
        if (dlg.RunModal () == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to print the document here...",
                MessageText = "Print Document",
            };
            alert.RunModal ();
        }
    }
}

Pokud vlastnost nastavíme ShowPrintAsSheet na false, spusťte aplikaci a zobrazíme dialogové okno rozložení při tisku, zobrazí se následující:

A page setup dialog

Pokud vlastnost nastavíte ShowPrintAsSheet na true, spusťte aplikaci a zobrazte dialogové okno rozložení při tisku, zobrazí se následující:

A page setup sheet

Další informace o práci s dialogovými okny Tisk a Vzhled stránky najdete v dokumentaci k NSPrintPanel a NSPageLayout společnosti Apple.

Dialogové okno Uložit

Dialogové okno Uložit umožňuje uživatelům konzistentní způsob, jak uložit položku v aplikaci.

Následující kód zobrazí standardní dialogové okno uložit:

public bool ShowSaveAsSheet { get; set;} = true;
...

[Export("saveDocumentAs:")]
void ShowSaveAs (NSObject sender)
{
    var dlg = new NSSavePanel ();
    dlg.Title = "Save Text File";
    dlg.AllowedFileTypes = new string[] { "txt", "html", "md", "css" };

    if (ShowSaveAsSheet) {
        dlg.BeginSheet(mainWindowController.Window,(result) => {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        });
    } else {
        if (dlg.RunModal () == 1) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        }
    }

}

Vlastnost AllowedFileTypes je pole řetězců typů souborů, které uživatel může vybrat k uložení souboru jako. Typ souboru může být zadán jako přípona nebo UTI. Výchozí hodnota je null, která umožňuje použití libovolného typu souboru.

Pokud vlastnost nastavíme ShowSaveAsSheet na false, spusťte aplikaci a v nabídce Soubor vyberte Uložit jako... následující:

A save dialog box

Uživatel může dialogové okno rozbalit:

An expanded save dialog box

Pokud vlastnost nastavíme ShowSaveAsSheet na true, spusťte aplikaci a v nabídce Soubor vyberte Uložit jako... následující:

A save sheet

Uživatel může dialogové okno rozbalit:

An expanded save sheet

Další informace o práci s dialogovým oknem Uložit najdete v dokumentaci k NSSavePanel společnosti Apple.

Shrnutí

Tento článek se podrobně podíval na práci s Modálními Windows, Listy a standardními systémovými dialogovými okny v aplikaci Xamarin.Mac. Viděli jsme různé typy a použití modálních oken, listů a dialogů, jak vytvářet a udržovat modální okna a listy v Tvůrci rozhraní Xcode a jak pracovat s modálními okny, listy a dialogy v kódu jazyka C#.