Xamarin.Mac での .storyboard/.xib のないユーザー インターフェイスの設計

この記事では、.storyboard ファイル、.xib ファイル、インターフェイス ビルダーを使用せずに、C# コードから Xamarin.Mac アプリケーションのユーザー インターフェイスを直接作成する方法について説明します。

概要

Xamarin.Mac アプリケーションで C# と .NET を使用する場合は、開発者が作業しているのと Xcode と同じユーザー インターフェイス要素とツールにObjective-Cアクセスできます。 通常、Xamarin.Mac アプリケーションを作成するときは、Xcode の Interface Builder と .storyboard または .xib ファイルを使用して、アプリケーションのユーザー インターフェイスを作成してメインします。

また、Xamarin.Mac アプリケーションの UI の一部またはすべてを C# コードで直接作成することもできます。 この記事では、C# コードでのユーザー インターフェイスと UI 要素の作成の基本について説明します。

The Visual Studio for Mac code editor

コードを使用するようにウィンドウを切り替える

新しい Xamarin.Mac Cocoa アプリケーションを作成すると、既定で標準の空白ウィンドウが表示されます。 このウィンドウは、プロジェクトに自動的に 含まれる Main.storyboard (または従来 は MainWindow.xib) ファイルで定義されています。 これには、アプリのメイン ビューを管理するViewController.cs ファイルも含まれます (または、従来は MainWindow.csMainWindowController.cs ファイル)。

アプリケーションの Xibless ウィンドウに切り替えるには、次の操作を行います。

  1. Visual Studio for Mac でユーザー インターフェイスを定義するために、使用 .storyboard を停止するアプリケーションまたは .xib ファイルを開きます。

  2. Solution Pad で、Main.storyboard または MainWindow.xib ファイルを右クリックし、[削除] を選択します

    Removing the main storyboard or window

  3. [削除] ダイアログで、[削除] ボタンをクリックして、プロジェクトから .storyboard または .xib を完全に削除します。

    Confirming the deletion

ここで、MainWindow.cs ファイルを変更してウィンドウのレイアウトを定義し、ViewController.csまたはMainWindowController.cs ファイルを変更してクラスのMainWindowインスタンスを作成する必要があります。.storyboard または .xib ファイルは使用しなくなったためです。

ユーザー インターフェイスにストーリーボードを使用する最新の 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 要素 an 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 には特定 の Label 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 の機能を使用できます。

  • 罫線なし - ウィンドウに罫線はありません。
  • タイトル - ウィンドウにタイトル バーが表示されます。
  • Closable - ウィンドウには閉じるボタンがあり、閉じることができます。
  • 小型化 - ウィンドウは小型化ボタンを備え、最小化することができます。
  • サイズ変更可能 - ウィンドウにはサイズ変更ボタンがあり、サイズを変更できます。
  • ユーティリティ - ウィンドウはユーティリティ スタイル ウィンドウ (パネル) です。
  • DocModal - ウィンドウがパネルの場合は、システム モーダルではなくドキュメント モーダルになります。
  • NonactivatingPanel - ウィンドウがパネルの場合、メイン ウィンドウには表示されません。
  • TexturedBackground - ウィンドウにはテクスチャ付きの背景が表示されます。
  • スケーリング なし - ウィンドウはスケーリングされません。
  • UnifiedTitleAndToolbar - ウィンドウのタイトルとツール バー領域が結合されます。
  • Hud - ウィンドウはヘッドアップディスプレイパネルとして表示されます。
  • FullScreenWindow - ウィンドウは全画面表示モードに切り替えることができます。
  • FullSizeContentView - ウィンドウのコンテンツ ビューは、タイトルとツール バー領域の背後にあります。

最後の 2 つのプロパティは、ウィンドウの バッファリングの種類 を定義し、ウィンドウの描画が遅延される場合。 詳細については、Apple の Windows の概要に関NSWindowsするドキュメントを参照してください。

最後に、ウィンドウは .storyboard または .xib ファイルから拡張されていないため、windows 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);

この時点で、アプリケーションが実行され、ボタンが数回クリックされた場合、次の内容が表示されます。

An example app run

コードのみのウィンドウを追加する

既存の Xamarin.Mac アプリケーションにコード xibless ウィンドウのみを追加する場合は、ソリューション パッドでプロジェクトを右クリックし、[新しいファイルの追加>] を選択します。[新しいファイル] ダイアログで、次に示すように Xamarin.Mac>Cocoa Window with Controller を選択します。

Adding a new window controller

前と同様に、プロジェクトから既定の .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 追加されて表示されます。 基本的に、.storyboard または .xib ファイルで Xcode のインターフェイス ビルダーで定義できる 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);
}

上記では、コードからステータス バー メニューが作成され、アプリケーションの起動時に表示されます。 メニューの操作の詳細については、メニューのドキュメントを参照してください。

まとめ

この記事では、Xcode の Interface Builder と .storyboard または .xib ファイルを使用するのではなく、C# コードで Xamarin.Mac アプリケーションのユーザー インターフェイスを作成する方法について詳しく説明しました。