Xamarin.Mac のダイアログ
Xamarin.Mac アプリケーションで C# と .NET を使用する場合は、作業している開発者と Xcode が行うのと同じダイアログとモーダル ウィンドウにObjective-Cアクセスできます。 Xamarin.Mac は Xcode と直接統合されるため、Xcode の Interface Builder を使用してモーダル ウィンドウを作成および保守できます (または必要に応じて、C# コードで直接作成することもできます)。
ユーザーアクションに応答してダイアログが表示され、通常はユーザーがアクションを完了する方法が提供されます。 ダイアログを閉じる前に、ユーザーからの応答が必要です。
Windows は、モードレス状態 (複数のドキュメントを一度に開くことができるテキスト エディターなど) またはモーダル (アプリケーションを続行する前に閉じる必要がある [エクスポート] ダイアログなど) で使用できます。
この記事では、Xamarin.Mac アプリケーションでのダイアログとモーダル Windows の操作の基本について説明します。 この記事で使用する主要な概念と手法については、「 Hello, Mac 」の記事、特 に「Xcode とインターフェイス ビルダー と アウトレットとアクション の概要」セクションを最初に説明することを強くお勧めします。
Xamarin.Mac Internals ドキュメントの「C# クラス/メソッドを Xamarin.Mac Internals に公開するObjective-C」セクションも参照してください。C# クラスObjective-Cをオブジェクトと UI 要素に結び付けるために使用される コマンドと Export
コマンドについても説明Register
しています。
ダイアログの概要
ユーザー アクション (ファイルの保存など) に応答するダイアログが表示され、ユーザーがそのアクションを完了する方法が提供されます。 ダイアログを閉じる前に、ユーザーからの応答が必要です。
Apple によると、ダイアログを表示するには、次の 3 つの方法があります。
- ドキュメント モーダル - ドキュメント モーダル ダイアログを使用すると、ユーザーは無視されるまで、特定のドキュメント内で他の操作を実行できなくなります。
- アプリ モーダル - アプリ モーダル ダイアログを使用すると、ユーザーはアプリケーションを閉じるまで操作できなくなります。
- モードレス モードレス ダイアログを使用すると、ユーザーはドキュメント ウィンドウを操作しながらダイアログの設定を変更できます。
モーダル ウィンドウ
NSWindow
標準は、モーダルで表示することで、カスタマイズされたダイアログとして使用できます。
ドキュメント モーダル ダイアログ シート
シートは、特定のドキュメント ウィンドウに添付されたモーダル ダイアログであり、ユーザーがダイアログを閉じるまでウィンドウを操作できなくなります。 シートは表示元のウィンドウにアタッチされ、1 つのウィンドウに対して一度に開くことができるシートは 1 つだけです。
環境設定ウィンドウ
ユーザー設定ウィンドウは、ユーザーが頻繁に変更しないアプリケーションの設定を含むモードレス ダイアログです。 ユーザー設定ウィンドウには、多くの場合、ユーザーがさまざまな設定グループを切り替えできるようにするツール バーが含まれています。
ダイアログを開く
[開く] ダイアログでは、アプリケーションでアイテムを一貫して検索して開く方法をユーザーに提供します。
[印刷とページ設定] ダイアログ
macOS には、ユーザーが使用するすべてのアプリケーションで一貫した印刷エクスペリエンスを実現できるように、アプリケーションで表示できる標準の [印刷] ダイアログと [ページ設定] ダイアログが用意されています。
[印刷] ダイアログは、次の両方のフリー フローティング ダイアログ ボックスとして表示できます。
または、シートとして表示することもできます。
[ページ設定] ダイアログは、次の両方のフリー フローティング ダイアログ ボックスとして表示できます。
または、シートとして表示することもできます。
[保存] ダイアログ
[保存] ダイアログボックスを使用すると、ユーザーはアプリケーションにアイテムを一貫して保存できます。 [保存] ダイアログには、 最小 (折りたたみ) という 2 つの状態があります。
展開された状態は次のとおりです。
[最小限の保存] ダイアログボックスはシートとして表示することもできます。
[展開された保存] ダイアログと同様に、次の操作を行います。
詳細については、「Apple の OS X ヒューマン インターフェイス ガイドライン」の「ダイアログ」セクションを参照してください。
プロジェクトへのモーダル ウィンドウの追加
メインドキュメント ウィンドウとは別に、Xamarin.Mac アプリケーションでは、環境設定やインスペクター パネルなど、他の種類のウィンドウをユーザーに表示する必要がある場合があります。
新しいウィンドウを追加するには、次の操作を行います。
ソリューション エクスプローラーで、Xcode の
Main.storyboard
インターフェイス ビルダーで編集用の ファイルを開きます。新しい ビュー コントローラー をデザイン サーフェイスにドラッグします。
[Identity Inspector]\(ID インスペクター\) で、[クラス名] に「」と入力
CustomDialogController
します。Visual Studio for Macに戻り、Xcode と同期してファイルを
CustomDialogController.h
作成できるようにします。Xcode に戻り、インターフェイスを設計します。
ダイアログを開く UI 要素からダイアログのウィンドウにコントロールをドラッグして、アプリのメイン ウィンドウから新しいビュー コントローラーに モーダル セグエ を作成します。 識別子
ModalSegue
を割り当てます。アクションとアウトレットをワイヤアップする:
変更を保存し、Visual Studio for Macに戻って Xcode と同期します。
ファイルを CustomDialogController.cs
次のようにします。
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
}
}
このコードでは、ダイアログのタイトルと説明を設定するためのいくつかのプロパティと、キャンセルまたは受け入れられるダイアログに対応するいくつかのイベントを公開します。
次に、ファイルを編集し ViewController.cs
、 メソッドを PrepareForSegue
オーバーライドして、次のようにします。
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;
}
}
このコードは、Xcode の Interface Builder で定義したセグエをダイアログに初期化し、タイトルと説明を設定します。 また、ユーザーがダイアログ ボックスで行う選択も処理します。
アプリケーションを実行し、カスタム ダイアログを表示できます。
Xamarin.Mac アプリケーションでの Windows の使用の詳細については、 Windows の使用 に関するドキュメントを参照してください。
ユーザー設定シートの作成
シートは、特定のドキュメント ウィンドウに添付されたモーダル ダイアログであり、ユーザーがダイアログを閉じるまでウィンドウを操作できなくなります。 シートは表示元のウィンドウにアタッチされ、1 つのウィンドウに対して一度に開くことができるシートは 1 つだけです。
Xamarin.Mac でカスタム シートを作成するには、次の操作を行います。
ソリューション エクスプローラーで、Xcode の
Main.storyboard
インターフェイス ビルダーで編集用の ファイルを開きます。新しい ビュー コントローラー をデザイン サーフェイスにドラッグします。
ユーザー インターフェイスを設計する:
メイン ウィンドウから新しいビュー コントローラーに シート セグエ を作成します。
ID インスペクターで、ビュー コントローラーのクラスに次の名前を付けます
SheetViewController
。必要なアウトレットとアクションを定義します。
変更を保存し、Visual Studio for Macに戻って同期します。
次に、ファイルを SheetViewController.cs
編集し、次のようにします。
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
}
}
次に、ファイルを編集し ViewController.cs
、 メソッドを PrepareForSegue
編集して、次のようにします。
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;
}
}
アプリケーションを実行してシートを開くと、ウィンドウにアタッチされます。
環境設定ダイアログの作成
インターフェイス ビルダーでユーザー設定ビューをレイアウトする前に、ユーザー設定の切り替えを処理するカスタム セグエの種類を追加する必要があります。 新しいクラスをプロジェクトに追加し、 と呼びます ReplaceViewSeque
。 クラスを編集し、次のようにします。
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
}
}
カスタム セグエを作成したら、Xcode の Interface Builder に新しいウィンドウを追加して、ユーザー設定を処理できます。
新しいウィンドウを追加するには、次の操作を行います。
ソリューション エクスプローラーで、Xcode の
Main.storyboard
インターフェイス ビルダーで編集用のファイルを開きます。新しい ウィンドウ コントローラー をデザイン サーフェイスにドラッグします。
メニュー バー デザイナーの近くにウィンドウを配置します。
アタッチされたビュー コントローラーのコピーを作成します。ユーザー設定ビューにはタブが表示されます。
ライブラリから新しいツール バー コントローラーをドラッグします。
デザイン サーフェイスのウィンドウにドロップします。
ツール バーのデザインをレイアウトします。
Control-Clickし、各 ツール バー ボタン から上記で作成したビューにドラッグします。 [カスタム セグエの種類] を選択します。
新しいセグエを選択し、 [クラス ] を に
ReplaceViewSegue
設定します。デザイン 画面のメニュー バー Designerで、[アプリケーション メニュー] から [環境設定...] を選択し、control キーを押しながらクリックして [環境設定] ウィンドウにドラッグし、Show segue を作成します。
変更を保存し、Visual Studio for Macに戻って同期します。
コードを実行し、[アプリケーション] メニューから [環境設定...] を選択すると、ウィンドウが表示されます。
Windows とツール バーの操作の詳細については、 Windows と ツール バーに関するドキュメントを 参照してください。
設定の保存と読み込み
一般的な macOS アプリでは、ユーザーがアプリの [ユーザー設定] に変更を加えると、それらの変更は自動的に保存されます。 Xamarin.Mac アプリでこれを処理する最も簡単な方法は、1 つのクラスを作成して、すべてのユーザー設定を管理し、システム全体で共有することです。
最初に、プロジェクトに新 AppPreferences
しいクラスを追加し、 から NSObject
継承します。 ユーザー設定は、 データ バインディングとKey-Value コーディング を使用するように設計されています。これにより、ユーザー設定フォームを作成して維持するプロセスがはるかに簡単になります。 Preferences は少量の単純なデータ型で NSUserDefaults
構成されるため、組み込みを使用して値を格納および取得します。
ファイルを AppPreferences.cs
編集し、次のようにします。
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
}
}
このクラスには、 などのSaveInt
LoadColor
LoadInt
SaveColor
いくつかのヘルパー ルーチンが含まれています。これにより、NSUserDefaults
操作が容易になります。 また、 NSUserDefaults
を処理 NSColors
する組み込みの方法がないため、 NSColorToHexString
メソッドと NSColorFromHexString
メソッドを使用して、簡単に格納および取得できる Web ベースの 16 進文字列 (#RRGGBBAA
ここで AA
はアルファ透明度) に色を変換します。
ファイルで AppDelegate.cs
、アプリ全体で使用される AppPreferences オブジェクトのインスタンスを作成します。
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
...
環境設定を環境設定ビューに配線する
次に、Preference クラスを、上で作成した基本設定ウィンドウとビューの UI 要素に接続します。 インターフェイス ビルダーで、基本設定ビュー コントローラーを選択し、 IDENTITY Inspector に切り替えて、コントローラーのカスタム クラスを作成します。
Visual Studio for Macに戻って変更を同期し、新しく作成したクラスを開いて編集します。 クラスを次のようにします。
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
}
}
このクラスでは、AppDelegate へのアクセスを容易にするヘルパー App
プロパティが 2 つあります。 次に、 プロパティは Preferences
、このビューに配置された UI コントロールを使用して、データ バインディング用のグローバル AppPreferences クラスを公開します。
次に、ストーリーボード ファイルをダブルクリックして、インターフェイス ビルダーで再度開きます (上記の変更を確認してください)。 基本設定インターフェイスをビルドするために必要なすべての UI コントロールをビューにドラッグします。 各コントロールについて、 バインド インスペクター に切り替え、 AppPreference クラスの個々のプロパティにバインドします。
必要なすべてのパネル (ビュー コントローラー) と基本設定プロパティに対して、上記の手順を繰り返します。
開いているすべてのウィンドウにユーザー設定の変更を適用する
前述のように、一般的な macOS アプリでは、ユーザーがアプリの [ユーザー設定] に変更を加えると、それらの変更が自動的に保存され、ユーザーがアプリケーションで開いている可能性があるすべてのウィンドウに適用されます。
アプリの設定とウィンドウを慎重に計画および設計することで、このプロセスをエンド ユーザーに対してスムーズかつ透過的に行い、最小限のコーディング作業を行えます。
App Preferences を使用するウィンドウの場合は、 AppDelegate へのアクセスを容易にするために、次のヘルパー プロパティをコンテンツ ビュー コントローラーに追加します。
#region Application Access
public static AppDelegate App {
get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
}
#endregion
次に、ユーザーの設定に基づいてコンテンツまたは動作を構成するクラスを追加します。
public void ConfigureEditor() {
// General Preferences
TextEditor.AutomaticLinkDetectionEnabled = App.Preferences.SmartLinks;
TextEditor.AutomaticQuoteSubstitutionEnabled = App.Preferences.SmartQuotes;
...
}
ウィンドウが最初に開かれたときに構成メソッドを呼び出して、ユーザーの設定に準拠していることを確認する必要があります。
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Configure editor from user preferences
ConfigureEditor ();
...
}
次に、ファイルを AppDelegate.cs
編集し、次のメソッドを追加して、開いているすべてのウィンドウにユーザー設定の変更を適用します。
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 ();
}
}
}
次に、プロジェクトに PreferenceWindowDelegate
クラスを追加し、次のようになります。
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
}
}
これにより、環境設定ウィンドウが閉じると、開いているすべての Windows にユーザー設定の変更が送信されます。
最後に、基本設定ウィンドウ コントローラーを編集し、上記で作成したデリゲートを追加します。
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
}
}
これらの変更をすべて行った状態で、ユーザーがアプリの [環境設定] を編集して [環境設定] ウィンドウを閉じると、開いているすべての Windows に変更が適用されます。
[開く] ダイアログ
[ダイアログを開く] を使用すると、アプリケーション内のアイテムを一貫して検索して開く方法がユーザーに提供されます。 Xamarin.Mac アプリケーションで [開く] ダイアログを表示するには、次のコードを使用します。
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;
}
}
上記のコードでは、ファイルの内容を表示する新しいドキュメント ウィンドウを開きます。 このコードは、アプリケーションで必要な機能に置き換える必要があります。
を使用する場合は、次のプロパティを NSOpenPanel
使用できます。
- CanChooseFiles - ユーザーがファイルを選択できる場合
true
。 - CanChooseDirectories - ユーザーがディレクトリを選択できる場合
true
。 - AllowsMultipleSelection - ユーザーが一度に複数のファイルを選択できる場合
true
。 - ResolveAliases -
true
と エイリアスを選択すると、元のファイルのパスに解決されます。 - AllowedFileTypes - ユーザーが拡張子または UTI として選択できるファイルの種類の文字列配列です。 既定値は です
null
。これにより、任意のファイルを開くことができます。
メソッドはRunModal ()
、[ダイアログを開く] を表示し、ユーザーがファイルまたはディレクトリ (プロパティで指定) を選択できるようにし、ユーザーが [開く] ボタンをクリックすると を返1
します。
[ダイアログを開く] は、ユーザーが選択したファイルまたはディレクトリを、 プロパティ内 URL
の URL の配列として返します。
プログラムを実行し、[ファイル] メニューから [開く...] 項目を選択すると、次の情報が表示されます。
[印刷とページ設定] ダイアログ
macOS には、ユーザーが使用するすべてのアプリケーションで一貫した印刷エクスペリエンスを実現できるように、アプリケーションで表示できる標準の印刷およびページ設定ダイアログが用意されています。
次のコードは、標準の印刷ダイアログを表示します。
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 ();
}
}
}
プロパティを に ShowPrintAsSheet
設定し false
、アプリケーションを実行して印刷ダイアログを表示すると、次のように表示されます。
プロパティを ShowPrintAsSheet
に設定し true
、アプリケーションを実行して印刷ダイアログを表示すると、次の情報が表示されます。
次のコードは、[ページ レイアウト] ダイアログを表示します。
[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 ();
}
}
}
プロパティを ShowPrintAsSheet
に設定し false
、アプリケーションを実行し、印刷レイアウト ダイアログを表示すると、次の情報が表示されます。
プロパティを ShowPrintAsSheet
に設定し true
、アプリケーションを実行し、印刷レイアウト ダイアログを表示すると、次の情報が表示されます。
印刷およびページ設定ダイアログの操作の詳細については、Apple の NSPrintPanel と NSPageLayout のドキュメントを参照してください。
[保存] ダイアログ
[保存] ダイアログでは、アプリケーションにアイテムを保存するための一貫した方法がユーザーに提供されます。
次のコードは、標準の [保存] ダイアログを表示します。
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 ();
}
}
}
プロパティは AllowedFileTypes
、ユーザーがファイルを保存するために選択できるファイルの種類の文字列配列です。 ファイルの種類は、拡張子または UTI として指定できます。 既定値は です null
。これにより、任意のファイルの種類を使用できます。
プロパティを ShowSaveAsSheet
に設定するとfalse
、アプリケーションを実行し、[ファイル] メニューの [名前を付けて保存] を選択すると、次の内容が表示されます。
ユーザーはダイアログを展開できます。
プロパティを ShowSaveAsSheet
に設定するとtrue
、アプリケーションを実行し、[ファイル] メニューの [名前を付けて保存] を選択すると、次の内容が表示されます。
ユーザーはダイアログを展開できます。
[保存] ダイアログの操作の詳細については、Apple の NSSavePanel のドキュメントを参照してください。
まとめ
この記事では、Xamarin.Mac アプリケーションでのモーダル ウィンドウ、シート、標準システム ダイアログ ボックスの操作について詳しく説明しました。 モーダル ウィンドウ、シート、ダイアログのさまざまな種類と使用方法、Xcode のインターフェイス ビルダーでモーダル ウィンドウとシートを作成および管理する方法、および C# コードでモーダル ウィンドウ、シート、ダイアログを操作する方法について説明しました。