Cuadros de diálogo en Xamarin.Mac
Cuando se trabaja con C# y .NET en una aplicación de Xamarin.Mac, se tiene acceso a las mismas ventanas y paneles que un desarrollador que trabaje en Objective-C y Xcode. Dado que Xamarin.Mac se integra directamente con Xcode, puede usar Interface Builder de Xcode para crear y mantener las vistas de tabla (u opcionalmente crearlas directamente en código C#).
Aparece un cuadro de diálogo en respuesta a una acción del usuario y normalmente proporciona formas en que los usuarios pueden completar la acción. Un cuadro de diálogo requiere una respuesta del usuario antes de que se pueda cerrar.
Se pueden usar ventanas en un estado Modeless (por ejemplo, un editor de texto que puede tener varios documentos abiertos a la vez) o Modal (por ejemplo, un cuadro de diálogo Exportar que se debe descartar antes de que la aplicación pueda continuar).
En este artículo, trataremos los aspectos básicos del trabajo con diálogos y ventanas modales en una aplicación Xamarin.Mac. Se recomienda encarecidamente primero revisar el artículo Hello, Mac; específicamente las secciones Introducción a Xcode e Interface Builder y Salidas y acciones, ya que se abordan conceptos clave y técnicas que usaremos en este artículo.
También puede echar un vistazo a la sección Exponer clases o métodos de C# a Objective-C del documento sobre el funcionamiento interno de Xamarin.Mac, ya que en ella se explican los atributos Register
y Export
que se usan para conectar las clases de C# a objetos Objective-C y elementos de la interfaz de usuario.
Introducción a los diálogos
Aparece un cuadro de diálogo en respuesta a una acción del usuario (como guardar un archivo) y proporciona una manera de que los usuarios completen esa acción. Un cuadro de diálogo requiere una respuesta del usuario antes de que se pueda cerrar.
Según Apple, hay tres maneras de presentar un cuadro de diálogo:
- Modal de documento: un cuadro de diálogo modal de documento impide que el usuario haga nada más dentro de un documento determinado hasta que se descarte.
- Modal de la aplicación: un cuadro de diálogo modal de la aplicación impide que el usuario interactúe con la aplicación hasta que se descarte.
- Modeless A Modeless Dialog permite a los usuarios cambiar la configuración del cuadro de diálogo mientras interactúan con la ventana del documento.
Ventana modal
Cualquier estándar NSWindow
se puede usar como un cuadro de diálogo personalizado al mostrarlo de forma modal:
Hojas de diálogo modales de documento
Una Hoja es un cuadro de diálogo modal adjunto a una ventana de documento determinada, lo que impide que los usuarios interactúen con la ventana hasta que descarten el cuadro de diálogo. Una Hoja se adjunta a la ventana desde la que surge y solo se puede abrir una hoja para una ventana en cualquier momento.
Preferencias de Windows
Una ventana Preferencias es un cuadro de diálogo modeless que contiene la configuración de la aplicación que el usuario cambia con poca frecuencia. Las preferencias de Windows suelen incluir una barra de herramientas que permite al usuario cambiar entre diferentes grupos de configuración:
Abrir el cuadro de diálogo
El cuadro de diálogo Abrir proporciona a los usuarios una manera coherente de buscar y abrir un elemento en una aplicación:
Cuadros de diálogo imprimir y configurar páginas
macOS proporciona cuadros de diálogo de instalación de impresión y página estándar que la aplicación puede mostrar para que los usuarios puedan tener una experiencia de impresión coherente en cada aplicación que usen.
El cuadro de diálogo imprimir se puede mostrar como un cuadro de diálogo flotante libre:
O bien, se puede mostrar como una hoja:
El cuadro de diálogo Configurar página se puede mostrar como un cuadro de diálogo flotante libre:
O bien, se puede mostrar como una hoja:
Guardar cuadros de diálogo
El cuadro de diálogo Guardar proporciona a los usuarios una manera coherente de guardar un elemento en una aplicación. El cuadro de diálogo Guardar tiene dos estados: Mínimo (también conocido como Contraído):
Y el estado Expandido:
El cuadro de diálogo Guardar Mínimo también se puede mostrar como una hoja:
Como puede el cuadro de diálogo Guardar Expandido:
Para más información, consulte la sección Diálogos de las Directrices de interfaz humana de OS X de Apple
Agregar una ventana modal a un proyecto
Aparte de la ventana principal del documento, es posible que una aplicación de Xamarin.Mac tenga que mostrar otros tipos de ventanas al usuario, como Preferencias o Paneles de inspectores.
Para agregar una nueva ventana, haga lo siguiente:
En el Explorador de soluciones, abra el
Main.storyboard
archivo para editarlo en el Interface Builder de Xcode.Arrastre un nuevo controlador de vista a la Superficie de diseño:
En el Inspector de identidad, introduzca
CustomDialogController
para el Nombre de la clase:Vuelva a Visual Studio para Mac, permita que se sincronice con Xcode y cree el
CustomDialogController.h
archivo.Vuelva a Xcode y diseñe la interfaz:
Cree un Segue modal desde la ventana principal de la aplicación al nuevo controlador de vistas arrastrando desde el elemento de la interfaz de usuario que abrirá el cuadro de diálogo en la ventana del diálogo. Asigne el identificador
ModalSegue
:Conecte las Acciones y salidas:
Guarde los cambios y vuelva a Visual Studio para Mac para sincronizarlo con Xcode.
Edite el archivo CustomDialogController.cs
para que quede de la siguiente manera:
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
}
}
Este código expone algunas propiedades para establecer el título y la descripción del cuadro de diálogo y algunos eventos para reaccionar al diálogo que se va a cancelar o aceptar.
Para ello, edite el archivo ViewController.cs
, invalide el método PrepareForSegue
y haga que tenga un aspecto similar al siguiente:
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;
}
}
Este código inicializa el segue que definimos en el Interface Builder de Xcode en nuestro cuadro de diálogo y configura el título y la descripción. También controla la elección que realiza el usuario en el cuadro de diálogo.
Podemos ejecutar nuestra aplicación y mostrar el cuadro de diálogo personalizado:
Para obtener más información sobre el uso de ventanas en una aplicación de Xamarin.Mac, consulte nuestra documentación Trabajar con Windows.
Crear una hoja personalizada
Una Hoja es un cuadro de diálogo modal adjunto a una ventana de documento determinada, lo que impide que los usuarios interactúen con la ventana hasta que descarten el cuadro de diálogo. Una Hoja se adjunta a la ventana desde la que surge y solo se puede abrir una hoja para una ventana en cualquier momento.
Para crear una hoja personalizada en Xamarin.Mac, hagamos lo siguiente:
En el Explorador de soluciones, abra el
Main.storyboard
archivo para editarlo en el Interface Builder de Xcode.Arrastre un nuevo controlador de vista a la Superficie de diseño:
Diseñe la interfaz de usuario:
Cree un segue de hoja desde la ventana principal al nuevo controlador de vistas:
En el Inspector de identidad, asigne un nombre a la clase
SheetViewController
del controlador de vista :Defina las salidas y accionesnecesarias:
Guarde los cambios y vuelva a Visual Studio para Mac para sincronizar.
A continuación, edite el archivo SheetViewController.cs
y haga que tenga un aspecto similar al siguiente:
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
}
}
A continuación, edite el archivo ViewController.cs
, edite el método PrepareForSegue
y haga que tenga el siguiente aspecto:
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;
}
}
Si ejecutamos la aplicación y abremos la hoja, se adjuntará a la ventana:
Crear un cuadro de diálogo de preferencias
Antes de diseñar la vista de preferencias en el Interface Builder, tendremos que agregar un tipo de segue personalizado para controlar la conmutación de las preferencias. Agregue una nueva clase al proyecto y nómbrelo ReplaceViewSeque
. Edite la clase y haga que tenga el siguiente aspecto:
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 el segue personalizado creado, podemos agregar una nueva ventana en el Interface Builder de Xcode para controlar nuestras preferencias.
Para agregar una nueva ventana, haga lo siguiente:
En el Explorador de soluciones, abra el
Main.storyboard
archivo para editarlo en el Interface Builder de Xcode.Arrastre un nuevo controlador de ventana a la Superficie de diseño:
Organice la ventana cerca del diseñador de la barra de menús:
Cree copias del controlador de vistas adjunto, ya que habrá pestañas en la vista de preferencias:
Arrastre un nuevo controlador de barra de herramientas desde la biblioteca:
Y colóquelo en la ventana de la Superficie de diseño:
Diseñe el diseño de la barra de herramientas:
Control-Haga clic y arrastre desde cada botón de barra de herramientas a las vistas que creó anteriormente. Seleccione un tipo de segue personalizado:
Seleccione el nuevo Segue y establezca la clase en
ReplaceViewSegue
:En el Diseñador de la barra de menús de la Superficie de diseño, en el menú Aplicación, seleccione Preferencias..., haga clic en el control y arrástrelo hasta la ventana Preferencias para crear un elemento Mostrar segue:
Guarde los cambios y vuelva a Visual Studio para Mac para sincronizar.
Si ejecutamos el código y selecciona lasPreferencias... en el Menú aplicación, se mostrará la ventana:
Para obtener más información sobre cómo trabajar con Windows y Barras de herramientas, consulte nuestra documentación sobre Windows y Barras de herramientas.
Guardar y cargar preferencias
En una aplicación macOS típica, cuando el usuario realiza cambios en cualquiera de las preferencias de usuario de la aplicación, esos cambios se guardan automáticamente. La manera más fácil de controlar esto en una aplicación de Xamarin.Mac es crear una sola clase para administrar todas las preferencias del usuario y compartirla en todo el sistema.
En primer lugar, agregue una nueva clase AppPreferences
al proyecto y herede de NSObject
. Las preferencias se diseñarán para usar el enlace de datos y la codificación clave-valor, lo que hará que el proceso de creación y mantenimiento de las preferencias sea mucho más sencillo. Dado que las Preferencias constarán de una pequeña cantidad de tipos de datos simples, use el integrado para NSUserDefaults
almacenar y recuperar valores.
Edite el archivo AppPreferences.cs
para que quede de la siguiente manera:
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
}
}
Esta clase contiene algunas rutinas auxiliares como SaveInt
, LoadInt
, SaveColor
, LoadColor
etc. para facilitar el trabajo NSUserDefaults
. Además, dado que NSUserDefaults
no tiene una manera integrada de controlar NSColors
, los NSColorToHexString
métodos y NSColorFromHexString
se usan para convertir colores en cadenas hexadecimales basadas en web (#RRGGBBAA
donde AA
es la transparencia alfa) que se pueden almacenar y recuperar fácilmente.
En el archivo AppDelegate.cs
, cree una instancia del objeto AppPreferences que se usará en toda la aplicación:
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
...
Preferencias de cableado a vistas de preferencias
A continuación, conecte la clase Preference a los elementos de la interfaz de usuario en la ventana de preferencias y las vistas creadas anteriormente. En el Interface Builder, seleccione un controlador de vista de preferencias y cambie al Inspector de identidad, cree una clase personalizada para el controlador:
Vuelva a Visual Studio para Mac para sincronizar los cambios y abra la clase recién creada para su edición. Haga que la clase se parezca a lo siguiente:
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
}
}
Tenga en cuenta que esta clase ha hecho dos cosas aquí: En primer lugar, hay una propiedad auxiliar App
para facilitar el acceso a AppDelegate. En segundo lugar, la Preferences
propiedad expone la clase AppPreferences global para el enlace de datos con los controles de interfaz de usuario colocados en esta vista.
A continuación, haga doble clic en el archivo Storyboard para volver a abrirlo en el Interface Builder (y vea los cambios realizados anteriormente). Arrastre los controles de interfaz de usuario necesarios para crear la interfaz de preferencias en la vista. Para cada control, cambie al Inspector de enlace y enlace a las propiedades individuales de la clase AppPreference:
Repita los pasos anteriores para todos los paneles (Controladores de vista) y Propiedades de preferencia necesarios.
Aplicación de cambios de preferencias a todas las ventanas abiertas
Como se indicó anteriormente, en una aplicación macOS típica, cuando el usuario realiza cambios en cualquiera de las preferencias de usuario de la aplicación, esos cambios se guardan automáticamente y se aplican a cualquier ventana que el usuario pueda tener abierta en la aplicación.
La planeación y el diseño cuidadosos de las preferencias y ventanas de la aplicación permitirán que este proceso se produzca sin problemas y transparentemente al usuario final, con una cantidad mínima de trabajo de codificación.
Para cualquier ventana que consuma preferencias de aplicación, agregue la siguiente propiedad auxiliar a su controlador de vista de contenido para facilitar el acceso a AppDelegate:
#region Application Access
public static AppDelegate App {
get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion
A continuación, agregue una clase para configurar el contenido o el comportamiento en función de las preferencias del usuario:
public void ConfigureEditor() {
// General Preferences
TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
...
}
Debe llamar al método de configuración cuando se abra la ventana por primera vez para asegurarse de que se ajusta a las preferencias del usuario:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Configure editor from user preferences
ConfigureEditor ();
...
}
A continuación, edite el AppDelegate.cs
archivo y agregue el método siguiente para aplicar los cambios de preferencia a todas las ventanas abiertas:
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 ();
}
}
}
A continuación, agregue una nueva clase PreferenceWindowDelegate
al proyecto y haga que tenga un aspecto similar al siguiente:
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
}
}
Esto hará que los cambios de preferencia se envíen a todas las ventanas abiertas cuando se cierre la ventana de preferencias.
Por último, edite el controlador de ventana de preferencias y agregue el delegado creado anteriormente:
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 todos estos cambios implementados, si el usuario edita las preferencias de la aplicación y cierra la ventana preferencias, los cambios se aplicarán a todas las ventanas abiertas:
Cuadro de diálogo Abrir
El cuadro de diálogo Abrir proporciona a los usuarios una manera coherente de buscar y abrir un elemento en una aplicación. Para mostrar un cuadro de diálogo abrir en una aplicación de Xamarin.Mac, use el código siguiente:
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;
}
}
En el código anterior, estamos abriendo una nueva ventana de documento para mostrar el contenido del archivo. Deberá reemplazar este código por la funcionalidad que requiere la aplicación.
Las siguientes propiedades están disponibles al trabajar con NSOpenPanel
:
- CanChooseFiles : si
true
el usuario puede seleccionar archivos. - CanChooseDirectories : si
true
el usuario puede seleccionar directorios. - AllowsMultipleSelection : si
true
el usuario puede seleccionar más de un archivo a la vez. - ResolveAliases : si
true
selecciona y alias, lo resuelve en la ruta de acceso del archivo original. - AllowedFileTypes : es una matriz de cadenas de tipos de archivo que el usuario puede seleccionar como una extensión o UTI. El valor predeterminado es
null
, que permite abrir cualquier archivo.
El RunModal ()
método muestra el cuadro de diálogo Abrir y permite al usuario seleccionar archivos o directorios (según lo especificado por las propiedades) y devuelve 1
si el usuario hace clic en el botón Abrir.
El cuadro de diálogo Abrir devuelve los archivos o directorios seleccionados del usuario como una matriz de direcciones URL en la URL
propiedad.
Si ejecutamos el programa y seleccionamos el elemento Abrir... en el menú Archivo, se muestra lo siguiente:
Cuadros de diálogo imprimir y configurar páginas
macOS proporciona cuadros de diálogo de instalación de impresión y página estándar que la aplicación puede mostrar para que los usuarios puedan tener una experiencia de impresión coherente en cada aplicación que usen.
El código siguiente mostrará el cuadro de diálogo de impresión estándar:
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 ();
}
}
}
Si establecemos la ShowPrintAsSheet
propiedad en false
, ejecute la aplicación y muestre el cuadro de diálogo de impresión, se mostrará lo siguiente:
Si establece la ShowPrintAsSheet
propiedad en true
, ejecute la aplicación y muestre el cuadro de diálogo de impresión, se mostrará lo siguiente:
El código siguiente mostrará el cuadro de diálogo Diseño de página:
[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 ();
}
}
}
Si establecemos la ShowPrintAsSheet
propiedad en false
, ejecute la aplicación y muestre el cuadro de diálogo diseño de impresión, se mostrará lo siguiente:
Si establece la ShowPrintAsSheet
propiedad en true
, ejecute la aplicación y muestre el cuadro de diálogo diseño de impresión, se mostrará lo siguiente:
Para obtener más información sobre cómo trabajar con los cuadros de diálogo imprimir y configurar páginas, consulte la documentación de NSPrintPanel y NSPageLayout de Apple.
Cuadro de diálogo Guardar
El cuadro de diálogo Guardar proporciona a los usuarios una manera coherente de guardar un elemento en una aplicación.
El código siguiente mostrará el cuadro de diálogo Guardar estándar:
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
propiedad es una matriz de cadenas de tipos de archivo que el usuario puede seleccionar para guardar el archivo como. El tipo de archivo se puede especificar como una extensión o UTI. El valor predeterminado es null
, que permite usar cualquier tipo de archivo.
Si establecemos la ShowSaveAsSheet
propiedad en false
, ejecute la aplicación y seleccione Guardar como... en el menú Archivo, se mostrará lo siguiente:
El usuario puede expandir el cuadro de diálogo:
Si establecemos la ShowSaveAsSheet
propiedad en true
, ejecute la aplicación y seleccione Guardar como... en el menú Archivo, se mostrará lo siguiente:
El usuario puede expandir el cuadro de diálogo:
Para obtener más información sobre cómo trabajar con el cuadro de diálogo Guardar, consulte la documentación de NSSavePanelde Apple.
Resumen
En este artículo se ha tomado un vistazo detallado al trabajo con Ventanas modales, Hojas y cuadros de diálogo del sistema estándar en una aplicación de Xamarin.Mac. Hemos visto los diferentes tipos y usos de Ventanas modales, hojas y diálogos, cómo crear y mantener ventanas modales y hojas en el Interface Builder de Xcode y cómo trabajar con ventanas modales, hojas y diálogos en código de C#.
Vínculos relacionados
- Hello, Mac
- Menús
- Windows
- Barras de herramientas
- OS X Human Interface Guidelines (Directrices de interfaz humana de OS X)
- Introducción a Windows
- Introducción a Hojas
- Introducción a la impresión