In this article

Overview

When working with C# and .NET in a Xamarin.Mac application, you have access to the same user interface elements and tools that a developer working in Objective-C and Xcode does. Typically, when creating a Xamarin.Mac application, you'll use Xcode's Interface Builder with .storyboard or .xib files to create and maintain you application's user interface.

You also have the option of creating some or all of your Xamarin.Mac application's UI directly in C# code. In this article, we'll cover the basics of creating user interfaces and UI elements in C# code.

Switching a window to use code

When you create a new Xamarin.Mac Cocoa application, you get a standard blank, window by default. This windows is defined in a Main.storyboard (or traditionally a MainWindow.xib) file automatically included in the project. This also includes a ViewController.cs file that manages the app's main view (or again traditionally a MainWindow.cs and a MainWindowController.cs file).

To switch to a Xibless window for an application, do the following:

Open the application that you want to stop using .storyboard or .xib files to define the user interface in Visual Studio for Mac.

In the Solution Pad, right-click on the Main.storyboard or MainWindow.xib file and select Remove:

From the Remove Dialog, click the Delete button to remove the .storyboard or .xib completely from the project:

Now we'll need to modify the MainWindow.cs file to define the window's layout and modify the ViewController.cs or MainWindowController.cs file to create an instance of our MainWindow class since we are no longer using the .storyboard or .xib file.

Modern Xamarin.Mac apps that use Storyboards for their user interface may not automatically include the MainWindow.cs, ViewController.cs or MainWindowController.cs files. As required, simply add a new Empty C# Class to the project (Add > New File... > General > Empty Class) and name it the same as the missing file.

Defining the window in code

Next, edit the MainWindow.cs file and make it look like the following:

These will give us access to the UI elements that we are going to display on the window. Since the window isn't being inflated from a .storyboard or .xib file, we need a way to instantiate it (as we'll see later in the MainWindowController class). That's what this new constructor method does:

This is where we will design the layout of the window and place any UI elements needed to create the required user interface. Before we can add any UI elements to a window, it needs a Content View to contain the elements:

ContentView = new NSView (Frame);

This creates a Content View that will fill the window. Now we add our first UI element, an NSButton, to the window:

The first thing to note here is that, unlike iOS, macOS uses mathematical notation to define its window coordinate system. So the origin point is in the lower left hand corner of the window, with values increasing right and towards the upper right hand corner of the window. When we create the new NSButton, we take this into account as we define its position and size on screen.

The AutoresizingMask = NSViewResizingMask.MinYMargin property tells the button that we want it to stay in the same location from the top of the window when the window is resized vertically. Again, this is required because (0,0) is at the bottom left of the window.

Finally, the ContentView.AddSubview (ClickMeButton) method adds the NSButton to the Content View so that it will be displayed on screen when the application is run and the window displayed.

Next a label is added to the window that will display the number of times that the NSButton has been clicked:

Since macOS doesn't have a specific Label UI element, we've added a specially styled, non-editable NSTextField to act as a Label. Just like the button before, the size and location takes into account that (0,0) is at the bottom left of the window. The AutoresizingMask = NSViewResizingMask.WidthSizable | NSViewResizingMask.MinYMargin property is using the or operator to combine two NSViewResizingMask features. This will make the label stay in the same location from the top of the window when the window is resized vertically and shrink and grow in width as the window is resized horizontally.

Again, the ContentView.AddSubview (ClickMeLabel) method adds the NSTextField to the Content View so that it will be displayed on screen when the application is run and the window opened.

Adjusting the window controller

Since the design of the MainWindow is no longer being loaded from a .storyboard or .xib file, we'll need to make some adjustments to the window controller. Edit the MainWindowController.cs file and make it look like the following:

We define the location of the window of screen with a CGRect. Just like the coordinate system of the window, the screen defines (0,0) as the lower left hand corner. Next, we define the style of the window by using the Or operator to combine two or more NSWindowStyle features:

Miniaturizable - The window has a Miniaturize Button and can be minimized.

Resizable - The window will have a Resize Button and be resizable.

Utility - The window is a Utility style window (panel).

DocModal - If the window is a Panel, it will be Document Modal instead of System Modal.

NonactivatingPanel - If the window is a Panel, it will not be made the main window.

TexturedBackground - The window will have a textured background.

Unscaled - The window will not be scaled.

UnifiedTitleAndToolbar - The window's title and toolbar areas will be joined.

Hud - The window will be displayed as a heads-up display Panel.

FullScreenWindow - The window can enter full screen mode.

FullSizeContentView - The window's content view is behind the title and toolbar Area.

The last two properties define the Buffering Type for the window and if drawing of the window will be deferred. For more information on NSWindows, please see Apple's Introduction to Windows documentation.

Finally, since the window isn't being inflated from a .storyboard or .xib file, we need to simulate it in our MainWindowController.cs by calling the windows AwakeFromNib method:

Window.AwakeFromNib ();

This will allow you to code against the window just like a standard window loaded from a .storyboard or .xib file.

Displaying the window

With the .storyboard or .xib file removed and the MainWindow.cs and MainWindowController.cs files modified, you'll be using the window just as you would any normal window that had been created in Xcode's Interface Builder with a .xib file.

The following will create a new instance of the window and its controller and display the window on screen:

At this point, if the application is run and the button clicked a couple of times, the following will be displayed:

Adding a code only window

If we want to add a code only, xibless window to an existing Xamarin.Mac application, right-click on the project in the Solution Pad and select Add > New File... In the New File dialog choose Xamarin.Mac > Cocoa Window with Controller, as illustrated below:

Just like before, we'll delete the default .storyboard or .xib file from the project (in this case SecondWindow.xib) and follow the steps in the Switching a Window to use Code section above to cover the window's definition to code.

Adding a UI element to a window in code

Whether a window was created in code or loaded from a .storyboard or .xib file, there might be times where we want to add a UI element to a window from code. For example:

The above code creates a new NSButton and adds it to the MyWindow window instance for display. Basically any UI element that can be defined in Xcode's Interface Builder in a .storyboard or .xib file can be created in code and displayed in a window.

Defining the menu bar in code

Because of current limitations in Xamarin.Mac, it is not suggested that you create your Xamarin.Mac application's Menu Bar–NSMenuBar–in code but continue to use the Main.storyboard or MainMenu.xib file to define it. That said, you can add and remove Menus and Menu Items in C# code.

For example, edit the AppDelegate.cs file and make the DidFinishLaunching method look like the following: