Okna dialogowe na platformie Xamarin.Mac
Podczas pracy z językami C# i .NET w aplikacji platformy Xamarin.Mac masz dostęp do tych samych okien dialogowych i modalnych, które wykonuje deweloper pracujący w Objective-C środowisku Xcode. Ponieważ platforma Xamarin.Mac integruje się bezpośrednio z programem Xcode, możesz użyć narzędzia Interface Builder środowiska Xcode, aby utworzyć i obsługiwać modalny system Windows (lub opcjonalnie utworzyć je bezpośrednio w kodzie języka C#).
Okno dialogowe jest wyświetlane w odpowiedzi na akcję użytkownika i zazwyczaj zapewnia sposób, w jaki użytkownicy mogą ukończyć akcję. Okno dialogowe wymaga odpowiedzi od użytkownika, zanim będzie można go zamknąć.
System Windows może być używany w stanie Modeless (na przykład edytor tekstu, który może mieć wiele dokumentów otwieranych jednocześnie) lub modalny (na przykład okno dialogowe Eksportowanie, które musi zostać odrzucone, zanim aplikacja będzie mogła kontynuować).
W tym artykule omówimy podstawy pracy z oknami dialogowymi i modalnymi systemami Windows w aplikacji platformy Xamarin.Mac. Zdecydowanie zaleca się, aby najpierw zapoznać się z artykułem Hello, Mac , w szczególności wprowadzenie do narzędzi Xcode i Interface Builder i Outlet and Actions , ponieważ obejmuje ona kluczowe pojęcia i techniki, których będziemy używać w tym artykule.
Warto zapoznać się również z sekcją Uwidacznianie klas/ metod Objective-C języka C# w dokumencie Xamarin.Mac Internals . Register
Objaśnienie poleceń i Export
używanych do podłączania klas języka C# do Objective-C obiektów i elementów interfejsu użytkownika.
Wprowadzenie do okien dialogowych
Zostanie wyświetlone okno dialogowe w odpowiedzi na akcję użytkownika (na przykład zapisanie pliku) i umożliwia użytkownikom ukończenie tej akcji. Okno dialogowe wymaga odpowiedzi od użytkownika, zanim będzie można go zamknąć.
Według Apple istnieją trzy sposoby prezentowania okna dialogowego:
- Modalny dokument — modalne okno dialogowe dokumentu uniemożliwia użytkownikowi wykonywanie niczego innego w danym dokumencie, dopóki nie zostanie ono odrzucone.
- Modalne aplikacje — modalne okno dialogowe aplikacji uniemożliwia użytkownikowi interakcję z aplikacją, dopóki nie zostanie odrzucona.
- Modeless Okno dialogowe bez moderowania umożliwia użytkownikom zmianę ustawień w oknie dialogowym podczas interakcji z oknem dokumentu.
Modalne okno
Dowolny standard NSWindow
może być używany jako dostosowane okno dialogowe, wyświetlając go modalnie:
Arkusze okien dialogowych modalnych dokumentu
Arkusz to modalne okno dialogowe, które jest dołączone do danego okna dokumentu, co uniemożliwia użytkownikom interakcję z oknem, dopóki nie odrzuci okna dialogowego. Arkusz jest dołączony do okna, z którego się pojawia i tylko jeden arkusz może być otwarty dla okna w dowolnym momencie.
Preferencje systemu Windows
Okno preferencji to okno bez moderowania zawierające ustawienia aplikacji, które użytkownik zmienia rzadko. Preferencje systemu Windows często zawierają pasek narzędzi, który umożliwia użytkownikowi przełączanie się między różnymi grupami ustawień:
Otwieranie okna dialogowego
Otwarte okno dialogowe zapewnia użytkownikom spójny sposób znajdowania i otwierania elementu w aplikacji:
Okna dialogowe Ustawienia wydruku i strony
System macOS udostępnia standardowe okna dialogowe Ustawienia wydruku i strony, które aplikacja może wyświetlać, aby użytkownicy mogli korzystać ze spójnego środowiska drukowania w każdej używanej aplikacji.
Okno dialogowe Drukowanie może być wyświetlane jako wolne przestawne okno dialogowe:
Można go również wyświetlić jako arkusz:
Okno dialogowe Ustawienia strony może być wyświetlane jako wolne przestawne okno dialogowe:
Można go również wyświetlić jako arkusz:
Okna dialogowe Zapisywania
Okno dialogowe Zapisywanie zapewnia użytkownikom spójny sposób zapisywania elementu w aplikacji. Okno dialogowe Zapisywanie ma dwa stany: Minimalny (znany również jako Zwinięty):
I stan Rozwinięty:
Okno dialogowe Minimalne zapisywanie może być również wyświetlane jako arkusz:
Jak można rozwinąć okno dialogowe Zapisywanie:
Aby uzyskać więcej informacji, zobacz sekcję Dialogs (Okna dialogowe) wytycznych dotyczących interfejsu człowieka systemu OS X firmy Apple
Dodawanie modalnego okna do projektu
Oprócz głównego okna dokumentu aplikacja Xamarin.Mac może wymagać wyświetlenia innych typów okien dla użytkownika, takich jak Preferencje lub Panele inspektorów.
Aby dodać nowe okno, wykonaj następujące czynności:
W Eksplorator rozwiązań otwórz
Main.storyboard
plik do edycji w narzędziu Interface Builder programu Xcode.Przeciągnij nowy kontroler widoku do powierzchni projektowej:
W inspektorze tożsamości wprowadź
CustomDialogController
nazwę klasy:Wróć do Visual Studio dla komputerów Mac, zezwól na synchronizację z programem Xcode i utwórz
CustomDialogController.h
plik.Wróć do środowiska Xcode i zaprojektuj interfejs:
Utwórz modalny segue z okna głównego aplikacji do nowego kontrolera widoku, przeciągając kontrolkę z elementu interfejsu użytkownika, który otworzy okno dialogowe do okna dialogowego. Przypisz identyfikator
ModalSegue
:Podłączanie wszystkich akcji i placówek:
Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację z programem Xcode.
CustomDialogController.cs
Utwórz plik w następujący sposób:
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
}
}
Ten kod uwidacznia kilka właściwości, aby ustawić tytuł i opis okna dialogowego oraz kilka zdarzeń reagujące na anulowanie lub zaakceptowanie okna dialogowego.
Następnie zmodyfikuj ViewController.cs
plik, zastąpij metodę PrepareForSegue
i ustaw ją tak:
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;
}
}
Ten kod inicjuje segue zdefiniowany w narzędziu Interface Builder programu Xcode do naszego okna dialogowego i konfiguruje tytuł i opis. Obsługuje również wybór, który użytkownik wykonuje w oknie dialogowym.
Możemy uruchomić naszą aplikację i wyświetlić okno dialogowe niestandardowe:
Aby uzyskać więcej informacji na temat korzystania z systemu Windows w aplikacji platformy Xamarin.Mac, zobacz dokumentację dotyczącą pracy z systemem Windows .
Tworzenie arkusza niestandardowego
Arkusz to modalne okno dialogowe, które jest dołączone do danego okna dokumentu, co uniemożliwia użytkownikom interakcję z oknem, dopóki nie odrzuci okna dialogowego. Arkusz jest dołączony do okna, z którego się pojawia i tylko jeden arkusz może być otwarty dla okna w dowolnym momencie.
Aby utworzyć arkusz niestandardowy na platformie Xamarin.Mac, wykonajmy następujące czynności:
W Eksplorator rozwiązań otwórz
Main.storyboard
plik do edycji w narzędziu Interface Builder programu Xcode.Przeciągnij nowy kontroler widoku do powierzchni projektowej:
Projektowanie interfejsu użytkownika:
Utwórz segue arkusza z okna głównego do nowego kontrolera widoku:
W inspektorze tożsamości nazwij klasę
SheetViewController
kontrolera widoku:Zdefiniuj wszystkie wymagane punkty i akcje:
Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację.
Następnie zmodyfikuj SheetViewController.cs
plik i utwórz go w następujący sposób:
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
}
}
Następnie zmodyfikuj plik, zmodyfikuj ViewController.cs
metodę PrepareForSegue
i ustaw ją tak:
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;
}
}
Jeśli uruchomimy aplikację i otworzymy arkusz, zostanie on dołączony do okna:
Okno dialogowe Tworzenie preferencji
Zanim ułożymy widok preferencji w narzędziu Interface Builder, musimy dodać niestandardowy typ segue, aby obsłużyć przełączanie preferencji. Dodaj nową klasę do projektu i wywołaj ją ReplaceViewSeque
. Zmodyfikuj klasę i ustaw ją tak, jakby wyglądała następująco:
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
}
}
Po utworzeniu niestandardowego segue możemy dodać nowe okno w narzędziu Interface Builder programu Xcode, aby obsłużyć nasze preferencje.
Aby dodać nowe okno, wykonaj następujące czynności:
W Eksplorator rozwiązań otwórz
Main.storyboard
plik do edycji w narzędziu Interface Builder programu Xcode.Przeciągnij nowy kontroler okna na powierzchnię projektową:
Rozmieść okno w pobliżu projektanta paska menu:
Utwórz kopie dołączonego kontrolera widoku, ponieważ w widoku preferencji będą znajdować się karty:
Przeciągnij nowy kontroler paska narzędzi z biblioteki:
I upuść go na oknie na powierzchni projektowej:
Układ projektu paska narzędzi:
Kliknij i przeciągnij z każdego przycisku paska narzędzi do widoków utworzonych powyżej. Wybierz niestandardowy typ segue:
Wybierz nowy segue i ustaw klasę na :
ReplaceViewSegue
W Projektancie paska menu na powierzchni projektowej z menu aplikacji wybierz pozycję Preferencje..., kliknij i przeciągnij do okna Preferencje, aby utworzyć segue Show:
Zapisz zmiany i wróć do Visual Studio dla komputerów Mac, aby przeprowadzić synchronizację.
Jeśli uruchomimy kod i wybierzemy pozycję Preferencje... z menu Aplikacji, zostanie wyświetlone okno:
Aby uzyskać więcej informacji na temat pracy z systemami Windows i Paskami narzędzi, zobacz dokumentację dotyczącą okien i pasków narzędzi.
Zapisywanie i ładowanie preferencji
W typowej aplikacji systemu macOS, gdy użytkownik wprowadza zmiany w dowolnej preferencji użytkownika aplikacji, te zmiany są zapisywane automatycznie. Najprostszym sposobem obsługi tej funkcji w aplikacji platformy Xamarin.Mac jest utworzenie jednej klasy do zarządzania wszystkimi preferencjami użytkownika i udostępniania jej całego systemu.
Najpierw dodaj nową AppPreferences
klasę do projektu i dziedzicz z NSObject
klasy . Preferencje zostaną zaprojektowane tak, aby korzystały z powiązania danych i kodowania klucz-wartość, dzięki czemu proces tworzenia i obsługi formularzy preferencji będzie znacznie prostszy. Ponieważ preferencje będą składać się z niewielkiej ilości prostych typów danych, użyj wbudowanej funkcji NSUserDefaults
do przechowywania i pobierania wartości.
Zmodyfikuj AppPreferences.cs
plik i utwórz go w następujący sposób:
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
}
}
Ta klasa zawiera kilka procedur pomocników, takich jak SaveInt
, LoadInt
, SaveColor
, LoadColor
itp., aby ułatwić pracę NSUserDefaults
. Ponadto, ponieważ NSUserDefaults
nie ma wbudowanego sposobu obsługi NSColors
, NSColorToHexString
metody i NSColorFromHexString
są używane do konwertowania kolorów na internetowe ciągi szesnastkowe (#RRGGBBAA
gdzie AA
jest przezroczystość alfa), które można łatwo przechowywać i pobierać.
AppDelegate.cs
W pliku utwórz wystąpienie obiektu AppPreferences, które będzie używane dla całej aplikacji:
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
...
Preferencje okablowania do widoków preferencji
Następnie połącz klasę preferencji z elementami interfejsu użytkownika w oknie preferencji i widokami utworzonymi powyżej. W narzędziu Interface Builder wybierz kontroler widoku preferencji i przejdź do inspektora tożsamości, utwórz niestandardową klasę dla kontrolera:
Wróć do Visual Studio dla komputerów Mac, aby zsynchronizować zmiany i otworzyć nowo utworzoną klasę do edycji. Ustaw klasę tak, jakby wyglądała następująco:
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
}
}
Zwróć uwagę, że ta klasa wykonała w tym miejscu dwie rzeczy: Najpierw istnieje właściwość pomocnika App
, aby ułatwić dostęp do elementu AppDelegate . Po drugie właściwość Preferences
uwidacznia globalną klasę AppPreferences na potrzeby powiązania danych z dowolnymi kontrolkami interfejsu użytkownika umieszczonymi w tym widoku.
Następnie kliknij dwukrotnie plik Scenorysu, aby otworzyć go ponownie w narzędziu Interface Builder (i zobacz zmiany wprowadzone powyżej). Przeciągnij wszystkie kontrolki interfejsu użytkownika wymagane do skompilowania interfejsu preferencji do widoku. Dla każdej kontrolki przejdź do inspektora powiązań i powiąż z poszczególnymi właściwościami klasy AppPreference:
Powtórz powyższe kroki dla wszystkich wymaganych paneli (kontrolerów widoku) i właściwości preferencji.
Stosowanie zmian preferencji do wszystkich otwartych okien
Jak wspomniano powyżej, w typowej aplikacji systemu macOS, gdy użytkownik wprowadza zmiany w dowolnej preferencji użytkownika aplikacji, te zmiany są zapisywane automatycznie i stosowane do wszystkich okien, które użytkownik mógł otworzyć w aplikacji.
Staranne planowanie i projektowanie preferencji i okien aplikacji umożliwi bezproblemowe i przejrzyste wykonanie tego procesu użytkownikowi końcowemu przy minimalnym liczbie prac związanych z kodowaniem.
W przypadku dowolnego okna, które będzie korzystać z preferencji aplikacji, dodaj następującą właściwość pomocnika do kontrolera widoku zawartości, aby ułatwić dostęp do naszej aplikacjiDelegate :
#region Application Access
public static AppDelegate App {
get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion
Następnie dodaj klasę, aby skonfigurować zawartość lub zachowanie na podstawie preferencji użytkownika:
public void ConfigureEditor() {
// General Preferences
TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
...
}
Należy wywołać metodę konfiguracji po pierwszym otwarciu okna, aby upewnić się, że jest ona zgodna z preferencjami użytkownika:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Configure editor from user preferences
ConfigureEditor ();
...
}
Następnie zmodyfikuj AppDelegate.cs
plik i dodaj następującą metodę, aby zastosować wszelkie zmiany preferencji do wszystkich otwartych okien:
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 ();
}
}
}
Następnie dodaj klasę PreferenceWindowDelegate
do projektu i utwórz ją w następujący sposób:
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
}
}
Spowoduje to wysłanie wszelkich zmian preferencji do wszystkich otwartych systemu Windows po zamknięciu okna preferencji.
Na koniec zmodyfikuj kontroler okna preferencji i dodaj pełnomocnika utworzonego powyżej:
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
}
}
Po wprowadzeniu wszystkich tych zmian, jeśli użytkownik edytuje preferencje aplikacji i zamyka okno preferencji, zmiany zostaną zastosowane do wszystkich otwartych systemu Windows:
Otwarte okno dialogowe
Otwarte okno dialogowe zapewnia użytkownikom spójny sposób znajdowania i otwierania elementu w aplikacji. Aby wyświetlić otwarte okno dialogowe w aplikacji Xamarin.Mac, użyj następującego kodu:
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;
}
}
W powyższym kodzie otwieramy nowe okno dokumentu, aby wyświetlić zawartość pliku. Musisz zastąpić ten kod funkcją wymaganą przez aplikację.
Podczas pracy z programem NSOpenPanel
są dostępne następujące właściwości:
- CanChooseFiles — jeśli
true
użytkownik może wybrać pliki. - CanChooseDirectories — jeśli
true
użytkownik może wybrać katalogi. - AllowsMultipleSelection — jeśli
true
użytkownik może wybrać więcej niż jeden plik jednocześnie. - ResolveAliases — jeśli
true
wybierzesz i alias, rozpozna go w ścieżce oryginalnego pliku. - AllowedFileTypes — to tablica ciągów typów plików, które użytkownik może wybrać jako rozszerzenie lub utI. Wartość domyślna to
null
, która umożliwia otwieranie dowolnego pliku.
Metoda RunModal ()
wyświetla otwarte okno dialogowe i zezwala użytkownikowi na wybieranie plików lub katalogów (zgodnie z właściwościami) i zwraca 1
, jeśli użytkownik kliknie przycisk Otwórz .
Otwarte okno dialogowe zwraca wybrane pliki lub katalogi użytkownika jako tablicę adresów URL we URL
właściwości .
Jeśli uruchomimy program i wybierzemy element Otwórz... z menu Plik , zostanie wyświetlony następujący komunikat:
Okna dialogowe Ustawienia wydruku i strony
System macOS udostępnia standardowe okna dialogowe Ustawienia wydruku i strony, które aplikacja może wyświetlać, aby użytkownicy mogli korzystać ze spójnego środowiska drukowania w każdej używanej aplikacji.
W poniższym kodzie zostanie wyświetlone standardowe okno dialogowe drukowania:
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 ();
}
}
}
Jeśli ustawimy ShowPrintAsSheet
właściwość na false
, uruchom aplikację i wyświetlimy okno dialogowe drukowania, zostaną wyświetlone następujące elementy:
W przypadku ustawienia ShowPrintAsSheet
właściwości na true
, uruchom aplikację i wyświetl okno dialogowe drukowania, zostaną wyświetlone następujące elementy:
W poniższym kodzie zostanie wyświetlone okno dialogowe Układ strony:
[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 ();
}
}
}
Jeśli ustawimy ShowPrintAsSheet
właściwość na false
, uruchom aplikację i wyświetlimy okno dialogowe układu wydruku, zostaną wyświetlone następujące elementy:
Jeśli dla właściwości ustaw ShowPrintAsSheet
wartość true
, uruchom aplikację i wyświetl okno dialogowe układu wydruku, zostaną wyświetlone następujące elementy:
Aby uzyskać więcej informacji na temat pracy z oknami dialogowymi Konfiguracji wydruku i strony, zobacz dokumentację NSPrintPanel i NSPageLayout firmy Apple.
Okno dialogowe Zapisywanie
Okno dialogowe Zapisywanie zapewnia użytkownikom spójny sposób zapisywania elementu w aplikacji.
W poniższym kodzie zostanie wyświetlone standardowe okno dialogowe Zapisywanie:
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 ();
}
}
}
Właściwość AllowedFileTypes
jest tablicą ciągów typów plików, które użytkownik może wybrać, aby zapisać plik jako. Typ pliku można określić jako rozszerzenie lub utI. Wartość domyślna to null
, która umożliwia używanie dowolnego typu pliku.
Jeśli ustawimy ShowSaveAsSheet
właściwość na false
, uruchom aplikację i wybierz pozycję Zapisz jako... z menu Plik zostaną wyświetlone następujące opcje:
Użytkownik może rozwinąć okno dialogowe:
Jeśli ustawimy ShowSaveAsSheet
właściwość na true
, uruchom aplikację i wybierz pozycję Zapisz jako... z menu Plik zostaną wyświetlone następujące opcje:
Użytkownik może rozwinąć okno dialogowe:
Aby uzyskać więcej informacji na temat pracy z dialogiem zapisywania, zobacz dokumentację NSSavePanel firmy Apple.
Podsumowanie
W tym artykule szczegółowo przedstawiono pracę z modalnymi oknami, arkuszami i standardowymi oknami dialogowymi systemu w aplikacji Xamarin.Mac. Zobaczyliśmy różne typy i zastosowania modalnych okien, arkuszy i okien dialogowych, jak tworzyć i obsługiwać modalne okna i arkusze w konstruktorze interfejsów Xcode oraz jak pracować z modalnymi oknami, arkuszami i oknami dialogowymi w kodzie języka C#.