Xamarin.Mac での .storyboard/.xib なしのユーザー インターフェイスの設計
この記事では、.storyboard ファイル、.xib ファイル、または Interface Builder を使用せずに、C# コードから直接 Xamarin.Mac アプリケーションのユーザー インターフェイスを作成する方法について説明します。
概要
Xamarin.Mac アプリケーションで C# と .NET を使用している場合、Objective-C と Xcode を使用する開発者が使用しているのと同じユーザー インターフェイス要素とツールを使用できます。 通常、Xamarin.Mac アプリケーションを作成するときは、Xcode の Interface Builder と .storyboard または .xib ファイルを使用して、アプリケーションのユーザー インターフェイスを作成および管理します。
また、Xamarin.Mac アプリケーションの UI の一部またはすべてを C# コードで直接作成することもできます。 この記事では、C# コードでユーザー インターフェイスと UI 要素を作成する基本について説明します。
ウィンドウを切り替えてコードを使用する
新しい Xamarin.Mac Cocoa アプリケーションを作成すると、既定で標準の空白のウィンドウが表示されます。 このウィンドウは、プロジェクトに自動的に含まれる Main.storyboard (または従来の MainWindow.xib) ファイルで定義されています。 これには、アプリのメイン ビューを管理する ViewController.cs ファイル (または従来の MainWindow.cs ファイルと MainWindowController.cs ファイル) も含まれます。
アプリケーションを Xibless ウィンドウに切り替えるには、次の手順を実行します。
Visual Studio for Mac でユーザー インターフェイスを定義するために .
.storyboard
または .xib ファイルの使用を停止するアプリケーションを開きます。Solution Pad で、Main.storyboard または MainWindow.xib ファイルを右クリックし、[削除] を選択します。
削除ダイアログで [削除] ボタンをクリックして、.storyboard または .xib をプロジェクトから完全に削除します。
次に、.storyboard ファイルまたは .xib ファイルは使用しなくなったため、MainWindow.cs ファイルを変更してウィンドウのレイアウトを定義し、ViewController.cs または MainWindowController.cs ファイルを変更して MainWindow
クラスのインスタンスを作成する必要があります。
ユーザー インターフェイスにストーリーボードを使用する最新の Xamarin.Mac アプリでは、MainWindow.cs、ViewController.cs、または MainWindowController.cs ファイルが自動的に含まれていない場合があります。 必要に応じて、プロジェクトに新しい空の C# クラスを追加し ([追加]>[新しいファイル]>[全般]>[空のクラス])、不足しているファイルと同じ名前を付けます。
コードでウィンドウを定義する
次に、MainWindow.cs ファイルを編集し、次のようにします。
using System;
using Foundation;
using AppKit;
using CoreGraphics;
namespace MacXibless
{
public partial class MainWindow : NSWindow
{
#region Private Variables
private int NumberOfTimesClicked = 0;
#endregion
#region Computed Properties
public NSButton ClickMeButton { get; set;}
public NSTextField ClickMeLabel { get ; set;}
#endregion
#region Constructors
public MainWindow (IntPtr handle) : base (handle)
{
}
[Export ("initWithCoder:")]
public MainWindow (NSCoder coder) : base (coder)
{
}
public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
// Define the user interface of the window here
Title = "Window From Code";
// Create the content view for the window and make it fill the window
ContentView = new NSView (Frame);
// Add UI elements to window
ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
AutoresizingMask = NSViewResizingMask.MinYMargin
};
ContentView.AddSubview (ClickMeButton);
ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
BackgroundColor = NSColor.Clear,
TextColor = NSColor.Black,
Editable = false,
Bezeled = false,
AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
StringValue = "Button has not been clicked yet."
};
ContentView.AddSubview (ClickMeLabel);
}
#endregion
#region Override Methods
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Wireup events
ClickMeButton.Activated += (sender, e) => {
// Update count
ClickMeLabel.StringValue = (++NumberOfTimesClicked == 1) ? "Button clicked one time." : string.Format("Button clicked {0} times.",NumberOfTimesClicked);
};
}
#endregion
}
}
いくつかの重要な要素について説明します。
まず、アウトレットのように (ウィンドウが .storyboard または .xib ファイルで作成された場合と同様に) 動作する "計算型プロパティ" をいくつか追加しました。
public NSButton ClickMeButton { get; set;}
public NSTextField ClickMeLabel { get ; set;}
これらにより、ウィンドウに表示する UI 要素にアクセスできるようになります。 ウィンドウは .storyboard または .xib ファイルから拡張されていないため、インスタンス化する方法が必要です (MainWindowController
クラスで後ほど説明します)。 この新しいコンストラクター メソッドがそれを実行します。
public MainWindow(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation): base (contentRect, aStyle,bufferingType,deferCreation) {
...
}
ここで、ウィンドウのレイアウトを設計し、必要なユーザー インターフェイスを作成するために必要な UI 要素を配置します。 ウィンドウに UI 要素を追加する前に、要素を含める "コンテンツ ビュー" が必要です。
ContentView = new NSView (Frame);
これにより、ウィンドウ全体に表示されるコンテンツ ビューが作成されます。 次に、最初の UI 要素である NSButton
をウィンドウに追加します。
ClickMeButton = new NSButton (new CGRect (10, Frame.Height-70, 100, 30)){
AutoresizingMask = NSViewResizingMask.MinYMargin
};
ContentView.AddSubview (ClickMeButton);
ここで最初に注意すべき点は、iOS とは異なり、macOS ではウィンドウの座標系を定義するために数学表記が使用されることです。 つまり、原点はウィンドウの左下隅にあり、値はウィンドウの右上隅に向かって右に増えていきます。 新しい NSButton
ファイルを作成するときは、画面上の位置とサイズを定義する際にこれを考慮します。
AutoresizingMask = NSViewResizingMask.MinYMargin
プロパティは、ウィンドウが垂直方向にサイズ変更されたときに、ボタンがウィンドウの上部から同じ位置に留まるように指示します。 繰り返しますが、(0,0) はウィンドウの左下にあるため、これは必須です。
最後に、ContentView.AddSubview (ClickMeButton)
メソッドは、NSButton
をコンテンツ ビューに追加して、アプリケーションが実行されウィンドウが表示されたときに画面に表示されるようにします。
次に、NSButton
がクリックされた回数を表示するラベルがウィンドウに追加されます。
ClickMeLabel = new NSTextField (new CGRect (120, Frame.Height - 65, Frame.Width - 130, 20)) {
BackgroundColor = NSColor.Clear,
TextColor = NSColor.Black,
Editable = false,
Bezeled = false,
AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin,
StringValue = "Button has not been clicked yet."
};
ContentView.AddSubview (ClickMeLabel);
macOS には特定の "ラベル" UI 要素がないため、ラベルとして機能する、特別なスタイルの編集不可能な NSTextField
を追加しました。 前のボタンと同様に、サイズと位置は (0,0) がウィンドウの左下にあることを考慮します。 AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin
プロパティは、or 演算子を使用して 2 つの NSViewResizingMask
機能を結合します。 これにより、ラベルは、ウィンドウが垂直方向にサイズ変更されたときにはウィンドウの上部から同じ位置に留まり、ウィンドウが水平方向にサイズ変更されたときには幅が縮小および拡大されます。
繰り返しになりますが、ContentView.AddSubview (ClickMeLabel)
メソッドは、NSTextField
をコンテンツ ビューに追加して、アプリケーションが実行されウィンドウが開いたときに画面に表示されるようにします。
ウィンドウ コントローラーを調整する
MainWindow
の設計が .storyboard または .xib ファイルから読み込まれなくなったため、ウィンドウ コントローラーにいくつかの調整を加える必要があります。 MainWindowController.cs ファイルを編集し、次のようにします。
using System;
using Foundation;
using AppKit;
using CoreGraphics;
namespace MacXibless
{
public partial class MainWindowController : NSWindowController
{
public MainWindowController (IntPtr handle) : base (handle)
{
}
[Export ("initWithCoder:")]
public MainWindowController (NSCoder coder) : base (coder)
{
}
public MainWindowController () : base ("MainWindow")
{
// Construct the window from code here
CGRect contentRect = new CGRect (0, 0, 1000, 500);
base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);
// Simulate Awaking from Nib
Window.AwakeFromNib ();
}
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
}
public new MainWindow Window {
get { return (MainWindow)base.Window; }
}
}
}
この変更の重要な要素について説明します。
まず、MainWindow
クラスの新しいインスタンスを定義し、それを基本ウィンドウ コントローラーの Window
プロパティに割り当てます。
CGRect contentRect = new CGRect (0, 0, 1000, 500);
base.Window = new MainWindow(contentRect, (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable), NSBackingStore.Buffered, false);
CGRect
を使用して画面のウィンドウの位置を定義します。 ウィンドウの座標系と同様に、画面は (0,0) を左下隅として定義します。 次に、Or 演算子を使用して 2 つ以上の NSWindowStyle
機能を組み合わせて、ウィンドウのスタイルを定義します。
... (NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable) ...
次の NSWindowStyle
機能が使用できます。
- Borderless - ウィンドウに境界線がありません。
- Titled - ウィンドウにタイトル バーがあります。
- Closable - ウィンドウに閉じるボタンがあり、閉じることができます。
- Miniaturizable - ウィンドウに最小化ボタンがあり、最小化することができます。
- Resizable - ウィンドウにサイズ変更ボタンがあり、サイズを変更できます。
- Utility - ウィンドウはユーティリティ スタイルのウィンドウ (パネル) です。
- DocModal - ウィンドウがパネルの場合、システム モーダルではなくドキュメント モーダルになります。
- NonactivatingPanel - ウィンドウがパネルの場合、メイン ウィンドウにはなりません。
- TexturedBackground - ウィンドウにテクスチャ付きの背景が表示されます。
- Unscaled - ウィンドウは拡大縮小されません。
- UnifiedTitleAndToolbar - ウィンドウのタイトルとツール バー領域が結合されます。
- Hud - ウィンドウはヘッドアップ ディスプレイ パネルとして表示されます。
- FullScreenWindow - ウィンドウを全画面表示モードにすることができます。
- FullSizeContentView - ウィンドウのコンテンツ ビューは、タイトルとツール バー領域の背後にあります。
最後の 2 つのプロパティは、ウィンドウの "バッファリングの種類" と、ウィンドウの描画が延期されるかどうかを定義します。 NSWindows
の詳細については、Apple のウィンドウの概要ドキュメントを参照してください。
最後に、ウィンドウは .storyboard または .xib ファイルから拡張されていないため、ウィンドウの AwakeFromNib
メソッドを呼び出して MainWindowController.cs でシミュレートする必要があります。
Window.AwakeFromNib ();
これにより、.storyboard または .xib ファイルから読み込まれた標準ウィンドウと同様に、ウィンドウに対してコードを記述できます。
ウィンドウを表示する
.storyboard または .xib ファイルを削除し、MainWindow.cs および MainWindowController.cs ファイルを変更すると、Xcode の Interface Builder で .xib ファイルを使用して作成した通常のウィンドウと同様に、ウィンドウを使用できるようになります。
以下は、ウィンドウとそのコントローラーの新しいインスタンスを作成し、ウィンドウを画面に表示します。
private MainWindowController mainWindowController;
...
mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);
この時点で、アプリケーションを実行し、ボタンを 2 回クリックすると、以下のように表示されます。
コードのみのウィンドウを追加する
既存の Xamarin.Mac アプリケーションにコードのみの xibles ウィンドウを追加する場合は、Solution Pad でプロジェクトを右クリックし、[追加]>[新しいファイル] を選択します。下図のように、[新しいファイル] ダイアログで [Xamarin.Mac]>[コントローラーを備えた Cocoa ウィンドウ] を選択します。
前と同じように、プロジェクトから既定の .storyboard または .xib ファイル (この場合は SecondWindow.xib) を削除し、上記の「ウィンドウを切り替えてコードを使用する」セクションの手順に従って、コードにウィンドウの定義を記述します。
コードでウィンドウに UI 要素を追加する
ウィンドウがコードで作成されたか、.storyboard または .xib ファイルから読み込まれたかにかかわらず、コードからウィンドウに UI 要素を追加したい場合があります。 次に例を示します。
var ClickMeButton = new NSButton (new CGRect (10, 10, 100, 30)){
AutoresizingMask = NSViewResizingMask.MinYMargin
};
MyWindow.ContentView.AddSubview (ClickMeButton);
上記のコードは、新しい NSButton
を作成し、それを MyWindow
ウィンドウ インスタンスに追加して表示します。 基本的に、Xcode の Interface Builder の .storyboard または .xib ファイルで定義できるすべての UI 要素をコードで作成し、ウィンドウに表示できます。
コードでメニュー バーを定義する
現在の Xamarin.Mac には制限があるため、Xamarin.Mac アプリケーションのメニューバー (NSMenuBar
) をコードで作成することは推奨されません。引き続き Main.storyboard または MainMenu.xib ファイルを使用して定義します。 ただし、C# コードでメニューとメニュー項目を追加および削除することは可能です。
たとえば、AppDelegate.cs ファイルを編集し、DidFinishLaunching
メソッドを次のようにします。
public override void DidFinishLaunching (NSNotification notification)
{
mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);
// Create a Status Bar Menu
NSStatusBar statusBar = NSStatusBar.SystemStatusBar;
var item = statusBar.CreateStatusItem (NSStatusItemLength.Variable);
item.Title = "Phrases";
item.HighlightMode = true;
item.Menu = new NSMenu ("Phrases");
var address = new NSMenuItem ("Address");
address.Activated += (sender, e) => {
Console.WriteLine("Address Selected");
};
item.Menu.AddItem (address);
var date = new NSMenuItem ("Date");
date.Activated += (sender, e) => {
Console.WriteLine("Date Selected");
};
item.Menu.AddItem (date);
var greeting = new NSMenuItem ("Greeting");
greeting.Activated += (sender, e) => {
Console.WriteLine("Greetings Selected");
};
item.Menu.AddItem (greeting);
var signature = new NSMenuItem ("Signature");
signature.Activated += (sender, e) => {
Console.WriteLine("Signature Selected");
};
item.Menu.AddItem (signature);
}
上記は、コードからステータス バー メニューを作成し、アプリケーションの起動時にそれを表示します。 メニューの操作の詳細については、メニューに関するドキュメントをご覧ください。
まとめ
この記事では、.storyboard または .xib ファイルで Xcode の Interface Builder を使用せずに、C# コードで Xamarin.Mac アプリケーションのユーザー インターフェイスを作成する方法について詳しく説明しました。