Dialoghi in Xamarin.Mac
Quando si lavora con C# e .NET in un'applicazione Xamarin.Mac, è possibile accedere alle stesse finestre di dialogo e windows modali che uno sviluppatore lavora in Objective-C e Xcode . Poiché Xamarin.Mac si integra direttamente con Xcode, è possibile usare Interface Builder di Xcode per creare e gestire Windows modale (o, facoltativamente, crearli direttamente nel codice C#).
Viene visualizzata una finestra di dialogo in risposta a un'azione dell'utente e in genere fornisce i modi in cui gli utenti possono completare l'azione. Una finestra di dialogo richiede una risposta dell'utente prima che possa essere chiusa.
Windows può essere usato in uno stato modeless (ad esempio un editor di testo che può avere più documenti aperti contemporaneamente) o modale (ad esempio una finestra di dialogo di esportazione che deve essere ignorata prima che l'applicazione possa continuare).
In questo articolo verranno illustrate le nozioni di base sull'uso di Dialoghi e Finestre modali in un'applicazione Xamarin.Mac. È consigliabile usare prima di tutto l'articolo Hello, Mac , in particolare le sezioni Introduzione a Xcode e Interface Builder e Outlet e Actions , in quanto illustra i concetti e le tecniche chiave che verranno usati in questo articolo.
È possibile esaminare anche la sezione Esposizione di classi/metodi C# al Objective-Cdocumento Internals di Xamarin.Mac, che illustra anche i Register
comandi e Export
usati per collegare le classi C# agli oggetti e agli Objective-C elementi dell'interfaccia utente.
Viene visualizzata una finestra di dialogo in risposta a un'azione dell'utente (ad esempio il salvataggio di un file) e consente agli utenti di completare tale azione. Una finestra di dialogo richiede una risposta dell'utente prima che possa essere chiusa.
Secondo Apple, esistono tre modi per presentare un dialogo:
- Modal documento: una finestra di dialogo Modale documento impedisce all'utente di eseguire qualsiasi altra operazione all'interno di un documento specificato fino a quando non viene chiusa.
- Modal dell'app: una finestra di dialogo Modale dell'app impedisce all'utente di interagire con l'applicazione fino a quando non viene chiusa.
- Un dialogo senza modalità consente agli utenti di modificare le impostazioni nella finestra di dialogo mentre interagisce ancora con la finestra del documento.
Qualsiasi standard NSWindow
può essere usato come finestra di dialogo personalizzata visualizzandola in modo modally:
Un foglio è una finestra di dialogo modale collegata a una determinata finestra di documento, impedendo agli utenti di interagire con la finestra fino a quando non chiude la finestra di dialogo. Un foglio è collegato alla finestra da cui emerge e un solo foglio può essere aperto per una finestra in qualsiasi momento.
Una finestra Preferenze è una finestra di dialogo senza modalità che contiene le impostazioni dell'applicazione che l'utente cambia raramente. Le preferenze di Windows includono spesso una barra degli strumenti che consente all'utente di passare da un gruppo di impostazioni all'altro:
La finestra di dialogo Apri offre agli utenti un modo coerente per trovare e aprire un elemento in un'applicazione:
macOS offre finestre di dialogo standard di installazione di stampa e pagina che l'applicazione può visualizzare in modo che gli utenti possano avere un'esperienza di stampa coerente in ogni applicazione usata.
È possibile visualizzare la finestra di dialogo Stampa come finestra di dialogo a virgola mobile libera:
Oppure può essere visualizzato come foglio:
La finestra di dialogo Imposta pagina può essere visualizzata come finestra di dialogo mobile libera:
Oppure può essere visualizzato come foglio:
La finestra di dialogo Salva offre agli utenti un modo coerente per salvare un elemento in un'applicazione. La finestra di dialogo salva ha due stati: Minimo (noto anche come Compresso):
E lo stato espanso :
La finestra di dialogo di salvataggio minimo può essere visualizzata anche come foglio:
Come può la finestra di dialogo Di salvataggio espanso :
Per altre informazioni, vedere la sezione Dialogs di Apple OS X Human Interface Guidelines
A parte la finestra del documento principale, potrebbe essere necessario che un'applicazione Xamarin.Mac visualizzi altri tipi di finestre all'utente, ad esempio Preferenze o Pannelli di controllo.
Per aggiungere una nuova finestra, eseguire le operazioni seguenti:
Nella Esplora soluzioni aprire il file per la
Main.storyboard
modifica in Interface Builder di Xcode.Trascinare un nuovo controller di visualizzazione nell'area di progettazione:
In Identity Inspector immettere
CustomDialogController
per Nome classe:Tornare a Visual Studio per Mac, consentire la sincronizzazione con Xcode e creare il
CustomDialogController.h
file.Tornare a Xcode e progettare l'interfaccia:
Creare un oggetto Modal Segue dalla finestra principale dell'app al nuovo controller di visualizzazione trascinando il controllo dall'elemento dell'interfaccia utente che aprirà la finestra di dialogo alla finestra del dialogo. Assegnare l'identificatore
ModalSegue
:Collegare eventuali azioni e punti vendita:
Salvare le modifiche e tornare a Visual Studio per Mac per la sincronizzazione con Xcode.
Fare in modo che il CustomDialogController.cs
file sia simile al seguente:
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
}
}
Questo codice espone alcune proprietà per impostare il titolo e la descrizione del dialogo e alcuni eventi per reagire alla finestra di dialogo annullata o accettata.
Modificare quindi il file, eseguire l'override ViewController.cs
del PrepareForSegue
metodo e renderlo simile al seguente:
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;
}
}
Questo codice inizializza il codice seguente definito in Interface Builder di Xcode nella finestra di dialogo e configura il titolo e la descrizione. Gestisce anche la scelta effettuata dall'utente nella finestra di dialogo.
È possibile eseguire l'applicazione e visualizzare la finestra di dialogo personalizzata:
Per altre informazioni sull'uso di windows in un'applicazione Xamarin.Mac, vedere la documentazione relativa all'uso di Windows .
Un foglio è una finestra di dialogo modale collegata a una determinata finestra di documento, impedendo agli utenti di interagire con la finestra fino a quando non chiude la finestra di dialogo. Un foglio è collegato alla finestra da cui emerge e un solo foglio può essere aperto per una finestra in qualsiasi momento.
Per creare un foglio personalizzato in Xamarin.Mac, eseguire le operazioni seguenti:
Nella Esplora soluzioni aprire il file per la
Main.storyboard
modifica in Interface Builder di Xcode.Trascinare un nuovo controller di visualizzazione nell'area di progettazione:
Progettare l'interfaccia utente:
Creare un foglio Segue dalla finestra principale al nuovo controller di visualizzazione:
In Identity Inspector denominare la classe
SheetViewController
del controller di visualizzazione :Definire gli outlet e le azioni necessari:
Salvare le modifiche e tornare a Visual Studio per Mac da sincronizzare.
Modificare quindi il SheetViewController.cs
file e renderlo simile al seguente:
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
}
}
Modificare quindi il ViewController.cs
file, modificare il PrepareForSegue
metodo e renderlo simile al seguente:
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;
}
}
Se si esegue l'applicazione e si apre il foglio, verrà collegato alla finestra:
Prima di definire la visualizzazione preferenza in Interface Builder, è necessario aggiungere un tipo segue personalizzato per gestire la disattivazione delle preferenze. Aggiungere una nuova classe al progetto e chiamarla ReplaceViewSeque
. Modificare la classe e renderla simile alla seguente:
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
}
}
Con la procedura personalizzata creata, è possibile aggiungere una nuova finestra in Interface Builder di Xcode per gestire le preferenze.
Per aggiungere una nuova finestra, eseguire le operazioni seguenti:
Nella Esplora soluzioni aprire il file per la
Main.storyboard
modifica in Interface Builder di Xcode.Trascinare un nuovo controller finestra nell'area di progettazione:
Disporre la finestra accanto alla finestra di progettazione della barra dei menu:
Creare copie del controller di visualizzazione collegato in quanto saranno presenti schede nella visualizzazione delle preferenze:
Trascinare un nuovo controller della barra degli strumenti dalla libreria:
E rilasciarlo nella finestra nell'area di progettazione:
Layout della struttura della barra degli strumenti:
Ctrl- Fare clic e trascinare da ogni pulsante della barra degli strumenti alle visualizzazioni create in precedenza. Selezionare un tipo di segue personalizzato :
Selezionare il nuovo Segue e impostare Classe su
ReplaceViewSegue
:Nell'area di progettazione della barra dei menu selezionare Preferenze dal menu Applicazione, fare clic e trascinare nella finestra Preferenze per creare una finestra Mostra segue:
Salvare le modifiche e tornare a Visual Studio per Mac da sincronizzare.
Se si esegue il codice e si seleziona Preferenze dal menu Applicazione, verrà visualizzata la finestra:
Per altre informazioni sull'uso di Windows e barre degli strumenti, vedere la documentazione di Windows e Barre degli strumenti .
In un'app macOS tipica, quando l'utente apporta modifiche a una delle preferenze utente dell'app, tali modifiche vengono salvate automaticamente. Il modo più semplice per gestirlo in un'app Xamarin.Mac consiste nel creare una singola classe per gestire tutte le preferenze dell'utente e condividerla a livello di sistema.
Aggiungere prima di tutto una nuova AppPreferences
classe al progetto ed ereditare da NSObject
. Le preferenze saranno progettate per l'uso del data binding e della codifica chiave-valore che renderanno molto più semplice il processo di creazione e gestione delle preferenze. Poiché le preferenze sono costituite da una piccola quantità di tipi di dati semplici, usare l'predefinito per NSUserDefaults
archiviare e recuperare i valori.
Modificare il AppPreferences.cs
file e renderlo simile al seguente:
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
}
}
Questa classe contiene alcune routine helper, ad SaveInt
esempio , , LoadInt
SaveColor
, LoadColor
e così via, per semplificare l'usoNSUserDefaults
. Inoltre, poiché NSUserDefaults
non dispone di un modo predefinito per gestire NSColors
, i NSColorToHexString
metodi e NSColorFromHexString
vengono usati per convertire i colori in stringhe esadecimali basate sul Web (#RRGGBBAA
dove AA
è la trasparenza alfa) che possono essere facilmente archiviate e recuperate.
AppDelegate.cs
Nel file creare un'istanza dell'oggetto AppPreferences che verrà usato a livello di app:
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
...
Connettere quindi la classe Preferenza agli elementi dell'interfaccia utente nella finestra preferenza e nelle visualizzazioni create in precedenza. In Interface Builder selezionare un controller di visualizzazione preferenza e passare a Identity Inspector, creare una classe personalizzata per il controller:
Tornare a Visual Studio per Mac per sincronizzare le modifiche e aprire la classe appena creata per la modifica. Fare in modo che la classe sia simile alla seguente:
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
}
}
Si noti che questa classe ha eseguito due operazioni: Prima di tutto, è disponibile una proprietà helper App
per semplificare l'accesso ad AppDelegate . In secondo luogo, la Preferences
proprietà espone la classe appPreferences globale per il data binding con tutti i controlli dell'interfaccia utente posizionati in questa visualizzazione.
Fare quindi doppio clic sul file Storyboard per riaprirlo in Interface Builder (e vedere le modifiche appena apportate in precedenza). Trascinare tutti i controlli dell'interfaccia utente necessari per compilare l'interfaccia delle preferenze nella visualizzazione. Per ogni controllo, passare a Binding Inspector e associarsi alle singole proprietà della classe AppPreference :
Ripetere i passaggi precedenti per tutti i pannelli (Controller di visualizzazione) e le proprietà delle preferenze necessari.
Come indicato in precedenza, in una tipica app macOS, quando l'utente apporta modifiche a una delle preferenze utente dell'app, tali modifiche vengono salvate automaticamente e applicate a qualsiasi finestra che l'utente potrebbe avere aperto nell'applicazione.
Un'attenta pianificazione e progettazione delle preferenze e delle finestre della tua app consentirà di eseguire questo processo in modo uniforme e trasparente all'utente finale, con una quantità minima di lavoro di codifica.
Per qualsiasi finestra che utilizza preferenze dell'app, aggiungere la proprietà helper seguente al controller visualizzazione contenuto per semplificare l'accesso ad AppDelegate :
#region Application Access
public static AppDelegate App {
get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion
Aggiungere quindi una classe per configurare il contenuto o il comportamento in base alle preferenze dell'utente:
public void ConfigureEditor() {
// General Preferences
TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
...
}
È necessario chiamare il metodo di configurazione quando la finestra viene aperta per la prima volta per assicurarsi che sia conforme alle preferenze dell'utente:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Configure editor from user preferences
ConfigureEditor ();
...
}
Modificare quindi il AppDelegate.cs
file e aggiungere il metodo seguente per applicare le modifiche alle preferenze a tutte le finestre aperte:
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 ();
}
}
}
Aggiungere quindi una PreferenceWindowDelegate
classe al progetto e renderla simile alla seguente:
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
}
}
In questo modo tutte le modifiche alle preferenze verranno inviate a tutte le finestre aperte alla chiusura della finestra di preferenza.
Modificare infine il controller finestra delle preferenze e aggiungere il delegato creato in precedenza:
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
}
}
Con tutte queste modifiche apportate, se l'utente modifica le preferenze dell'app e chiude la finestra delle preferenze, le modifiche verranno applicate a tutte le finestre aperte:
La finestra di dialogo Apri offre agli utenti un modo coerente per trovare e aprire un elemento in un'applicazione. Per visualizzare una finestra di dialogo aperta in un'applicazione Xamarin.Mac, usare il codice seguente:
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;
}
}
Nel codice precedente si apre una nuova finestra del documento per visualizzare il contenuto del file. È necessario sostituire questo codice con la funzionalità richiesta dall'applicazione.
Quando si utilizza un oggetto NSOpenPanel
, sono disponibili le proprietà seguenti:
- CanChooseFiles : se
true
l'utente può selezionare i file. - CanChooseDirectories : se
true
l'utente può selezionare le directory. - AllowsMultipleSelection : se
true
l'utente può selezionare più file alla volta. - ResolveAliases : se
true
si seleziona e alias, lo risolve nel percorso del file originale. - AllowedFileTypes : matrice di stringhe di tipi di file che l'utente può selezionare come estensione o UTI. Il valore predefinito è
null
, che consente l'apertura di qualsiasi file.
Il RunModal ()
metodo visualizza la finestra di dialogo Apri e consente all'utente di selezionare file o directory (come specificato dalle proprietà) e restituisce 1
se l'utente fa clic sul pulsante Apri .
La finestra di dialogo Apri restituisce i file o le directory selezionati dell'utente come matrice di URL nella URL
proprietà .
Se si esegue il programma e si seleziona la voce Apri dal menu File , viene visualizzato quanto segue:
macOS offre finestre di dialogo standard di installazione di stampa e pagina che l'applicazione può visualizzare in modo che gli utenti possano avere un'esperienza di stampa coerente in ogni applicazione usata.
Il codice seguente mostrerà la finestra di dialogo di stampa standard:
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 ();
}
}
}
Se si imposta la ShowPrintAsSheet
proprietà su false
, eseguire l'applicazione e visualizzare la finestra di dialogo di stampa, verrà visualizzato quanto segue:
Se si imposta la ShowPrintAsSheet
proprietà su true
, eseguire l'applicazione e visualizzare la finestra di dialogo di stampa, verrà visualizzato quanto segue:
Il codice seguente visualizzerà la finestra di dialogo Layout pagina:
[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 ();
}
}
}
Se si imposta la ShowPrintAsSheet
proprietà su false
, eseguire l'applicazione e visualizzare la finestra di dialogo layout di stampa, verrà visualizzato quanto segue:
Se si imposta la ShowPrintAsSheet
proprietà su true
, eseguire l'applicazione e visualizzare la finestra di dialogo layout di stampa, verrà visualizzato quanto segue:
Per altre informazioni sull'uso delle finestre di dialogo Di installazione di stampa e pagina, vedere la documentazione NSPrintPanel e NSPageLayout di Apple.
La finestra di dialogo Salva offre agli utenti un modo coerente per salvare un elemento in un'applicazione.
Il codice seguente mostrerà la finestra di dialogo di salvataggio standard:
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 ();
}
}
}
La AllowedFileTypes
proprietà è una matrice di stringhe di tipi di file che l'utente può selezionare per salvare il file con nome. Il tipo di file può essere specificato come estensione o UTI. Il valore predefinito è null
, che consente l'uso di qualsiasi tipo di file.
Se si imposta la ShowSaveAsSheet
proprietà su false
, eseguire l'applicazione e selezionare Salva con nome dal menu File , verrà visualizzato quanto segue:
L'utente può espandere la finestra di dialogo:
Se si imposta la ShowSaveAsSheet
proprietà su true
, eseguire l'applicazione e selezionare Salva con nome dal menu File , verrà visualizzato quanto segue:
L'utente può espandere la finestra di dialogo:
Per altre informazioni sull'uso della finestra di dialogo salva, vedere la documentazione di NSSavePanel di Apple.
Questo articolo ha esaminato in dettaglio l'uso di finestre modali, fogli e finestre di dialogo di sistema standard in un'applicazione Xamarin.Mac. Sono stati illustrati i diversi tipi e usi di finestre modali, fogli e finestre di dialogo, come creare e gestire finestre e fogli modali nel generatore di interfacce di Xcode e come usare finestre modali, fogli e dialoghi nel codice C#.