Dialogy v Xamarin.Macu

Při práci s C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným dialogovým oknům a modálním Windows jako vývojář pracující v aplikaci a Objective-CObjective-C 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ě modálního Windows (nebo je volitelně vytvořit přímo v kódu C#).

V reakci na akci uživatele se zobrazí dialogové okno, které obvykle uživatelům umožňuje akci dokončit. Dialogové okno vyžaduje odpověď od uživatele před jeho zavřením.

Windows lze použít v bezmodálním stavu (například v textovém editoru, který může mít najednou otevřených více dokumentů) nebo modální (například dialogové okno Export, které je nutné zavřít, aby aplikace pokračovala).

Otevřené dialogové okno

V tomto článku se budeme seznamovat se 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ě 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 příkazy a používané k připojení tříd jazyka C# k objektům a prvkům uživatelského RegisterExportObjective-C rozhraní.

Úvod do dialogových oknů

Zobrazí se dialogové okno v reakci na akci uživatele (například uložení souboru) a poskytuje uživatelům způsob, jak ji dokončit. Dialogové okno vyžaduje odpověď od uživatele před jeho zavřením.

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

  • Modální dialogové okno dokumentu – Modální dialogové okno dokumentu brání uživateli v tom, aby v daném dokumentu dělal cokoli jiného, dokud se nezamítl.
  • Modální dialogové okno aplikace – Modální dialogové okno brání uživateli v interakci s aplikací, dokud ji nezamítnou.
  • Nemodální Ne moderování dialogového okna umožňuje uživatelům změnit nastavení v dialogovém okně a přitom stále pracovat s oknem dokumentu.

Jakýkoli standard NSWindow můžete použít jako přizpůsobené dialogové okno, které se zobrazí modálně:

Příklad modálního okna

Modální listy dialogového okna dokumentu

List je modální dialogové okno, které je připojené k danému oknu dokumentu a brání uživatelům v interakci s oknem, dokud dialogové okno nezamítnou. List je připojený k oknu, ze kterého se objevuje, a pro okno lze najednou otevřít pouze jeden list.

Příklad modálního listu

Předvolby Windows

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

Příklad okna předvoleb

Otevření dialogového okna

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

Otevřené dialogové okno

MacOS poskytuje standardní dialogová okna tiskových a stránkových nastavení, která může vaše aplikace zobrazit, aby uživatelé mohli mít konzistentní tisk v každé aplikaci, kterou používají.

Dialogové okno Tisk se může zobrazit jako bezplatné plovoucí dialogové okno:

Dialogové okno tisku

Nebo se může zobrazit jako List:

Tiskový list

Dialogové okno Vzhled stránky se může zobrazit jako bezplatné plovoucí dialogové okno:

Dialogové okno pro nastavení stránky

Nebo se může zobrazit jako List:

List pro nastavení stránky

Uložení dialogových oknů

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

Dialogové okno pro uložení

A rozbalený stav:

Rozbalené dialogové okno pro uložení

Dialogové okno Minimální uložení se také může zobrazit jako List:

Minimální uložit list

Stejně jako v rozšířeném dialogovém okně Uložit:

Rozbalený uložit list

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

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

Kromě hlavního okna dokumentu může aplikace Xamarin.Mac potřebovat zobrazit uživateli jiné typy oken, například Předvolby nebo Panely inspektoru.

Nové okno přidáte takto:

  1. V Průzkumník řešeníotevřete soubor pro úpravy v souboru Xcode Interface Builder.

  2. Přetáhněte nový kontroler zobrazení do Návrhová plocha:

    Výběr kontroleru zobrazení z knihovny

  3. V Identity Inspectoru zadejte jako Název třídy:

    Nastavení názvu třídy na CustomDialogController

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

  5. Vraťte se do Xcode a navrhovat rozhraní:

    Návrh uživatelského rozhraní v Xcode

  6. Přetahováním ovládacích prvků z prvku uživatelského rozhraní vytvořte modální segénu z hlavního okna aplikace do nového kontroleru zobrazení, který otevře dialogové okno dialogového okna. Přiřaďte identifikátor :

    Modální se zamyšlené

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

    Konfigurace akce

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

Aby CustomDialogController.cs soubor vypadal 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 zpřístupňuje několik vlastností pro nastavení názvu a popisu dialogového okna a několik událostí, které reagují na zrušení nebo přijetí dialogového okna.

Dále upravte ViewController.cs soubor, přepište PrepareForSegue metodu a napište, aby vypadal 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 inicializuje segu, kterou jsme definovali v Xcode Interface Builder našeho dialogového okna a nastaví název a popis. Zpracovává také výběr, který uživatel v dialogovém okně provede.

Můžeme spustit naši aplikaci a zobrazit vlastní dialogové okno:

Příklad dialogového okna

Další informace o používání Windows v aplikaci Xamarin.Mac najdete v naší dokumentaci Práce Windows platformou.

Vytvoření vlastního listu

List je modální dialogové okno, které je připojené k danému oknu dokumentu a brání uživatelům v interakci s oknem, dokud dialogové okno nezamítnou. List je připojený k oknu, ze kterého se objevuje, a pro okno lze najednou otevřít pouze jeden list.

Pokud chcete vytvořit vlastní list v Xamarin.Macu, pustíme se do následujících kroků:

  1. V Průzkumník řešeníotevřete soubor pro úpravy v souboru Xcode Interface Builder.

  2. Přetáhněte nový kontroler zobrazení do Návrhová plocha:

    Výběr kontroleru zobrazení z knihovny

  3. Návrh uživatelského rozhraní:

    Návrh uživatelského rozhraní

  4. Z hlavního okna vytvořte List Se do nového kontroleru zobrazení:

    Výběr typu List

  5. V Identity Inspectorupojmete třídu kontroleru zobrazení :

    Nastavení názvu třídy na SheetViewController

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

    Definování požadovaných výstupů a akcí

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

V dalším kroku upravte SheetViewController.cs soubor tak, aby vypadal 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 PrepareForSegue metodu a vytvořte, aby vypadal 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 aplikaci spustíme a otevřeme List, připojí se k oknu:

Příklad listu

Vytvoření dialogového okna předvoleb

Než rozložíme zobrazení předvoleb v Interface Builder, bude potřeba přidat vlastní typ přechod pro zpracování přecházení na Předvolby. Přidejte do projektu novou třídu a zavolejte ji ReplaceViewSeque . Upravte třídu a nastavte ji jako následující:

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

    }

}

Když jste vytvořili vlastní přechod, můžeme do Interface Builder Xcodeu přidat nové okno pro zpracování našich předvoleb.

Chcete-li přidat nové okno, postupujte následovně:

  1. V Průzkumník řešeníotevřete soubor pro úpravy v Interface Builder Xcode.

  2. Přetáhněte nový kontroler oken do návrhová plocha:

    Vybrat řadič okna z knihovny

  3. Uspořádat okno poblíž návrháře panelu nabídek :

    Přidání nového okna

  4. Vytvořte kopie připojeného kontroleru zobrazení tak, jak se budou v zobrazení předvoleb zobrazovat na kartách:

    Přidání požadovaných řadičů zobrazení

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

    Vybrat kontroler panelu nástrojů z knihovny

  6. A přetáhněte ho do okna v Návrhová plocha:

    Přidává se nový kontroler panelů nástrojů.

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

    Rozložení panelu nástrojů

  8. Control-Click a přetáhněte je z každého tlačítka panelu nástrojů na zobrazení, která jste vytvořili výše. Vyberte vlastní typ přechod:

    Nastavení vlastního typu přechod.

  9. Vyberte nový přechod a nastavte třídu na :

    Nastavení třídy přechod

  10. V Návrháři MenuBar na návrhová plocha vyberte v nabídce aplikace Předvolby..., ovládací prvek – klikněte a přetáhněte ho do okna Předvolby a vytvořte tak přechod zobrazení :

    Nastavení typu přechod přetažením předvoleb do okna předvoleb.

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

Pokud kód spouštíme a v nabídce aplikacevyberete Předvolby... , zobrazí se okno:

Ukázka okna předvoleb, které zobrazuje profil aplikace Word.

další informace o práci s Windows a panely nástrojů najdete v dokumentaci pro Windows a panely nástrojů .

Předvolby ukládání a načítání

Když uživatel provede v typické aplikaci macOS změny v kterékoli z uživatelských preferencí aplikace, tyto změny se automaticky uloží. Nejjednodušší způsob, jak to zpracovat v aplikaci Xamarin. Mac, je vytvořit jednu třídu, která bude spravovat všechny předvolby uživatele a sdílet je v celém systému.

Nejprve přidejte AppPreferences do projektu novou třídu a z ní dědit NSObject . Předvolby budou sloužit k použití datových vazeb a kódování Key-Value , což zajistí mnohem jednodušší proces vytváření a údržby formulářů předvoleb. Vzhledem k tomu, že se tyto preference skládají z malého množství jednoduchých typů dat, použijte vestavěnou aplikaci NSUserDefaults pro ukládání a načítání hodnot.

Upravte AppPreferences.cs soubor a nastavte jeho vzhled jako na následující:

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 například SaveInt , LoadInt , SaveColor , LoadColor , atd., aby bylo NSUserDefaults snazší pracovat. Kromě toho vzhledem k tomu, že nemá NSUserDefaults vestavěný způsob zpracování NSColors , NSColorToHexStringNSColorFromHexString metody a slouží k převodu barev na webové řetězce hex ( #RRGGBBAA kde AA je průhlednost alfa), které lze snadno uložit a načíst.

V AppDelegate.cs souboru vytvořte instanci objektu AppDelegate.cs , která bude použita pro celé aplikace:

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 kabeláže do zobrazení předvoleb

Dále připojte třídu preference k prvkům uživatelského rozhraní v okně předvoleb a v zobrazeních, která jsou vytvořena výše. V Interface Builder vyberte kontroler zobrazení předvoleb a přepněte se na inspektora identity, vytvořte pro řadič vlastní třídu:

Inspektor identity

přepněte zpátky na Visual Studio pro Mac a synchronizujte změny a otevřete nově vytvořenou třídu pro úpravy. Nastavte, aby třída vypadala 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 provedla dvě věci: Nejdřív je k dispozici pomocná App vlastnost, která usnadňuje přístup k App . Za druhé Preferences vlastnost zpřístupňuje globální třídu Preferences 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 scénáře a znovu ho otevřete v Interface Builder (a podívejte se na změny, které jste provedli výše). Přetáhněte jakékoli ovládací prvky uživatelského rozhraní potřebné k sestavení rozhraní předvoleb do zobrazení. Pro každý ovládací prvek přepněte na inspektor vazby a vytvořte vazbu na jednotlivé vlastnosti třídy AppPreference :

Inspektor vazby

Opakujte výše uvedené kroky pro všechny panely (zobrazení řadičů) a požadované vlastnosti předvolby.

Použití změn předvoleb pro všechny otevřené Windows

Jak je uvedeno výše, v typické aplikaci macOS, když uživatel provede změny v kterékoli z uživatelských preferencí aplikace, tyto změny se uloží automaticky a uplatní se pro všechny uživatele, kteří v aplikaci můžou otevřít.

Pečlivé plánování a návrh předvoleb vaší aplikace a Windows umožní tomuto procesu hladce a transparentnímu uživateli, a to s minimálním množstvím práce s kódováním.

Pro všechna okna, která budou používat předvolby aplikace, přidejte následující vlastnost helper do svého kontroleru zobrazení obsahu, abyste měli přístup k našemu AppDelegateu snazší:

#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;
    ...

}

Je nutné zavolat metodu konfigurace při prvním otevření okna, abyste se ujistili, že odpovídá předvolbám uživatele:

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

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

V dalším kroku upravte AppDelegate.cs soubor a přidejte následující metodu, která aplikuje všechny změny předvoleb na všechna otevřená okna:

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

}

Dále přidejte PreferenceWindowDelegate do projektu třídu a nastavte ji jako následující:

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 všem otevřeným Windows při zavření okna předvoleb.

Nakonec upravte kontroler okna předvoleb a přidejte delegáta, který jste vytvořili 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, budou tyto změny aplikovány na všechny otevřené Windows:

Ukázka okna předvoleb zobrazená v několika dalších otevřených oknech.

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 otevřený dialog 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, ve kterém se zobrazí obsah souboru. Tento kód budete muset nahradit funkcí, kterou vaše aplikace vyžaduje.

Následující vlastnosti jsou k dispozici při práci s NSOpenPanel :

  • CanChooseFiles – Pokud uživatel může vybrat soubory.
  • CanChooseDirectories – Pokud uživatel může vybírat adresáře.
  • AllowsMultipleSelection – Pokud uživatel může současně vybrat více než jeden soubor.
  • ResolveAliases – Pokud vyberete a alias, přeloží se na cestu k původnímu souboru.
  • AllowedFileTypes – je pole řetězců typů souborů, které může uživatel vybrat buď jako rozšíření, nebo jako identifikátor UTI. Výchozí hodnota je null , což umožňuje otevřít libovolný soubor.

RunModal ()Metoda zobrazí dialog Otevřít a umožní uživateli vybrat soubory nebo adresáře (podle zadání vlastností) a vrátí, 1 Pokud uživatel klikne na tlačítko RunModal () .

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 vyberte položku otevřít... , zobrazí se následující:

Otevřené dialogové okno

Dialogová okna Tisk a vzhled stránky

macOS poskytuje standardní dialogová okna pro tisk a stránku, které může vaš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 Tisk:

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 nastavíme ShowPrintAsSheet vlastnost na false , spustíte aplikaci a zobrazí se dialogové okno Tisk, zobrazí se následující:

Dialogové okno Tisk

Pokud nastavíte ShowPrintAsSheet vlastnost na true , spustíte aplikaci a zobrazí se dialogové okno Tisk, zobrazí se následující:

List tisku

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 nastavíme ShowPrintAsSheet vlastnost na false , spustíte aplikaci a zobrazí se dialogové okno rozložení tisku, zobrazí se následující:

Dialogové okno nastavení stránky

Pokud nastavíte ShowPrintAsSheet vlastnost na true , spustíte aplikaci a zobrazí se dialogové okno rozložení tisku, zobrazí se následující:

List nastavení stránky

Další informace o práci s dialogy tisk a nastavení stránky najdete v dokumentaci k NSPrintPanel a NSPageLayout společnosti Apple.

Dialogové okno Uložit

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

Následující kód zobrazí standardní dialog 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 ();
        }
    }

}

AllowedFileTypesVlastnost je pole řetězců typů souborů, které může uživatel vybrat k uložení souboru jako. Typ souboru může být buď zadaný jako příponový, nebo identifikátor UTI. Výchozí hodnota je null , která umožňuje použití libovolného typu souboru.

Pokud nastavíme vlastnost na , spustíme aplikaci a v nabídce Soubor vybereme Uložit jako, zobrazí ShowSaveAsSheetfalse se následující: ShowSaveAsSheetfalse

Dialogové okno Uložit

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

Rozbalené dialogové okno pro uložení

Pokud nastavíme vlastnost na , spustíme aplikaci a v nabídce Soubor vybereme Uložit jako, zobrazí ShowSaveAsSheettrue se následující: ShowSaveAsSheettrue

Uložení listu

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

Rozbalený uložit list

Další informace o práci s dialogem Uložit najdete v dokumentaci k objektu NSSavePanel společnosti Apple.

Souhrn

Tento článek podrobně popisuje práci s modálními Windows, listy a standardními systémovými dialogy v aplikaci Xamarin.Mac. Viděli jsme různé typy a použití modálních Windows, listů a dialogových oknů, jak vytvářet a udržovat modální Windows a listy v Interface Builder Xcode a jak pracovat s modálními Windows, listy a dialogy v kódu jazyka C#.