Share via


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

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

概要

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

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

Visual Studio for Mac コード エディター

ウィンドウを切り替えてコードを使用する

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

アプリケーションを Xibless ウィンドウに切り替えるには、次の手順を実行します。

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

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

    メイン ストーリーボードまたはウィンドウを削除する

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

    削除を確認する

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

ユーザー インターフェイスにストーリーボードを使用する最新の Xamarin.Mac アプリでは、MainWindow.csViewController.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 アプリケーションのユーザー インターフェイスを作成する方法について詳しく説明しました。