Xamarin Tutorial
Xamarin Tutorial
Using Xamarin.Mac, you can create native Mac applications by using the same UI controls that you would if you were writing the application in Objective-C and Xcode, except you have the flexibility and elegance of a modern language (C#), the power of the .NET Base Class Library (BCL), and a first-class IDE (Xamarin Studio) at your fingertips. Additionally, Xamarin.Mac integrates directly with Xcode so that you can use the integrated Interface Builder (IB) to create your applications user interface. In this tutorial, were going to walk through creating a simple application from start to finish. Well cover the following items: Xamarin Studio (MD) Introduction to the Xamarin IDE (Xamarin Studio) and how to create Xamarin.Mac applications with it. Anatomy of a Xamarin.Mac Application What a Xamarin.Mac application consists of. Xcodes Interface Builder How to use Xcodes Interface Builder to define your applications user interface (UI). Outlets and Actions How to use Outlets and Actions to wire up controls in the UI. Deployment/Testing How to run your application and test it out.
The following is a screenshot of the application that were going to build, running in Mountain Lion (Mac OS X 10.8):
In the left-hand pane, choose C# > Xamarin.Mac, and then, in the center pane, select Xamarin.Mac Project template. This will create a new single window Mac application.
If you are using the trial, select "Mac (open source)" which uses the more limited set of APIs. Lets name it Hello_Mac. Choose a location where youd like the solution to reside, and click OK. Xamarin Studio will create a new Xamarin.Mac application and solution that looks something like the following:
This should be pretty familiar territory if youve used an IDE before. There is a Solution Explorer pad that shows all the files in the solution, and a code editor pad that allows you to view and edit the selected file. Xamarin Studio uses Solutions and Projects, the exact same way that Visual Studio does. A solution is a container that can hold one or more projects; projects can include applications, supporting libraries, test applications, etc. In this case, Xamarin Studio has created both a solution and an application project for you. If you wanted to, you could create code library projects that the application project uses, just as you would if you were building a standard .NET application.
The Project
If youre familiar with iOS programming, youll notice a lot of similarities here. In fact, iOS uses the CocoaTouch framework, which is a slimmed-town version of Cocoa, used by Mac. In fact, a lot of concepts will cross over here. Lets take a look at the files in the project:
G
This contains the main entry point of the application. When the application is launched, this contains the very first class and method that is run. AppDelegate.cs This file contains the main application class that is responsible for listening to events from the operating system.
Main.cs
This file contains application properties such as the application name, icons, etc. MainMenu.xib This is the UI for the application menu. .Xib files (also referred to as Nibs for legacy reasons), are XML files that contain the definition of views (UI elements). MainWindow.cs This is the class that represents the main window and controls the lifecycle of it. MainWindow.designer.cs This file contains plumbing code that helps you integrate with the main screens user interface. MainWindow.xib The UI for the main window. MainWindowController.cs This is the controller for the main window. Well cover controllers in the next guide, but for now, a controller can be thought of the main engine of any particular view.
Info.plist
Lets take a quick look through some of these files. Well explore them in more detail later, and in other tutorials, but its a good idea to understand their basics now.
Main.cs
The Main.cs file is very simple. It contains a static Main method which creates a new Xamarin.Mac application instance and passes the name of the class that will handle OS events, which in our case is the AppDelegate class:
using System; using System.Drawing; using MonoMac.Foundation; using MonoMac.AppKit; using MonoMac.ObjCRuntime; namespace Hello_Mac { class MainClass { static void Main (string[] args) { NSApplication.Init (); NSApplication.Main (args); } } }
AppDelegate.cs
The AppDelegate.cs file contains our AppDelegate class, which is responsible for creating our window and listening to OS events:
using System; using System.Drawing; using MonoMac.Foundation; using MonoMac.AppKit; using MonoMac.ObjCRuntime; namespace Hello_Mac { public partial class AppDelegate : NSApplicationDelegate { MainWindowController mainWindowController; public AppDelegate () { } public override void FinishedLaunching (NSObject notification) { mainWindowController = new MainWindowController (); mainWindowController.Window .MakeKeyAndOrderFront (this); } } }
This code is probably unfamiliar unless youve built an iOS application before, but its fairly simple. Lets examine the important lines. First, lets take a look at the two class-level variable declarations:
MainWindowController mainWindowController;
The MainWindowController declaration represents what controls the actual application window. Generally, for every window you create (and for many other things within windows), there is a controller, which is responsible for the windows life cycle, such as showing it, adding new views (controls) to it, etc. Cocoa (and by derivation, CocoaTouch) uses whats known as the Model View Controller (MVC) pattern. Well examine this in more depth in the next tutorial, when we create an application with multiple windows. Next, we have the FinishedLaunching method. This method runs after the application has been instantiated, and its responsible for actually creating the application window and beginning the process of displaying the view in it. The first line instantiates a new instance of our main window controller:
Next, the code tells the main window (the Window property on the controller) that it should be in focus and accept user input (Key), and appear in the front of any other windows:
mainWindowController.Window.MakeKeyAndOrderFront (this);
MainWindowController.cs
As weve already seen, the MainWindowController class is our main windows controller. That means its responsible for the life cycle of the main window. Were going to examine this in detail later, so we can skip any more detail about it for now:
using System; using System.Collections.Generic; using System.Linq; using MonoMac.Foundation; using MonoMac.AppKit; namespace Hello_Mac { public partial class MainWindowController : MonoMac.AppKit.NSWindowController { #region Constructors // Called when created from unmanaged code public MainWindowController (IntPtr handle) : base (handle) { Initialize (); } // Called when created directly from a XIB file [Export ("initWithCoder:")] public MainWindowController (NSCoder coder) : base (coder) { Initialize (); } // Call to load from the XIB/NIB file public MainWindowController () : base ("MainWindow") { Initialize (); } // Shared initialization code void Initialize () { } #endregion //strongly typed window accessor public new MainWindow Window { get { return (MainWindow)base.Window; } } } }
The Window property is a convenience property that casts the base.Window property to a strongly-typed version of the actual Window class, so that any properties on there (as well see later) are available without having to cast it every time you want to access them.
MainWindow.Designer.cs
The designer file for the Main Window class is empty right now, but it will be automatically populated by Xamarin Studio as we create our UI:
namespace Hello_Mac { // Should subclass MonoMac.AppKit.NSWindow [MonoMac.Foundation.Register("MainWindow")] public partial class MainWindow { } // Should subclass MonoMac.AppKit.NSWindowController [MonoMac.Foundation.Register("MainWindowController")] public partial class MainWindowController { } }
We arent usually concerned with designer files, as theyre just automatically managed by Xamarin Studio and just provide the requisite pluming code that allows access to controls that we add to any window or view in our application. Now that we have created our Xamarin.Mac application and we have a basic understanding of its components, lets jump over to Xcode and create our UI.
If Xcode doesnt open up, you can right-click on the file and choose Open With : Xcode. Lets do a quick overview of Xcode to orient ourselves.
Components of Xcode
When you open a Xib in Xcode from MD, Xcode opens with the Navigator Area on the left and the Editor Area in the middle, and the Utilities Area on the right:
When a .xib file is open, the Editor Area surface is whats known as Interface Builder (IB). In previous versions of Xcode, IB was a separate application. If you dont see the Utilities Area, you can make it display by clicking the far-right button in the View section of the toolbar:
The Utility Area is mostly empty because nothing is selected; however, if you select a control (or the main view), it will populate. The Utility Area is further broken down into two sub-areas, Inspector Tabs and Library Tabs:
In the Library Tabs Area, you can find controls and objects to place into the designer. The Inspector Tabs are kind of like property pages, where you can examine and edit control instances in the
designer. There are 8 different Inspector Tabs, as shown in the following illustration:
File Inspector New in Interface Builder 4, the File Inspector shows file information, such as the file name and location of the Xib file that is being edited. Quick Help Also new in Interface Builder 4, the Quick Help tab is part of Xcode 4s redesigned help system. It provides contextual help based on what is selected in Xcode. Identity Inspector The Identity Inspector provides information about the selected control/view. Attributes Inspector The Attributes Inspector allows you to customize various attributes of the selected control/view. Size Inspector The Size Inspector allows you to control the size and resizing behavior of the selected control/view. Connections Inspector The Connections Inspector shows the Outlet and Action connections of the selected controls. Well examine Outlets and Actions in just a moment. Bindings Inspector The Bindings Inspector allows you to configure controls so that their values are automatically bound to data models. View Effects Inspector The View Effects Inspector allows you to specify effects on the controls, such as animations.
To create this UI: 1. Drag a Push Button and a Label to the designer from the third tab of the Library. 2. To resize the controls, select them and then pull on their resize handles. 3. Double-click on the button to set its text. 4. Make the label nearly as wide as the view. This will let us update the label with text when the buttons are clicked. As youre resizing and moving controls around, youll notice that IB gives you helpful snap hints that are based on Apples Human Interface Guidelines (HIG). These guidelines will help you create high quality applications that will have a familiar look and feel for Mac users. While we have IB open, lets look at one other useful area, the Document Inspector. The Document Inspector is just to the left of the Editor Area and can be expanded by clicking the > arrow button at the bottom of the area:
The Document Inspector shows you all of the items in a tree and allows you to select them:
If you have a complicated UI, this can be a great alternative to using the designer window. OK, now that we have created our UI, we need to wire up our Outlets to code.
Outlets Outlets are analogous to properties. If you wire up a control to an Outlet, its exposed to your code via a property, so you can do things like attach event handlers, call methods on it, etc. Actions Actions are analogous to the command pattern in WPF. For example, when an Action is performed on a control, say a button click, the control will automatically call a method in your code. Actions are powerful and convenient because you can wire up many controls to the same Action.
In Xcode 4, Outlets and Actions are added directly in code via Control-dragging. More specifically, this means that in order to create an Outlet or Action, you choose which control element youd like to
add an Outlet or Action, hold down the Control button on the keyboard, and drag that control directly into your code. For Xamarin.Mac developers, this means that you drag into the Objective-C stub files that correspond to the C# file where you want to create the Outlet or Action. In order to facilitate this, Xcode 4 introduced a split-view in the Editor Area called the Assistant Editor that allows two files to be visible at once (the .xib file in the Interface Builder designer, and the code file in the code editor). In order to view the Assistant Editor split screen, click the middle button of the Editor choice buttons in the toolbar:
Now we can start wiring up our Outlets, we wont use Actions in this application, but the process is nearly exactly the same.
Adding an Outlet
Before we start to wire up our Outlets, we first need to make sure that theyre going to get wired up in the right file. In the Assistant Editor, choose the file drop down just above the editor, and make sure that the MainWindowController.h file is chosen:
In this case, we could wire up the Outlets to the window file, but in practice, Outlets are should nearly always be put in controllers (where theyll be used). So well get in the habit now. Once weve made sure that the right file is chosen, lets perform the following procedure to create our Outlets: 1. Determine for which control you want an Outlet. To start with, were going to create an outlet for the Click Me button. 2. Hold down the Control key on the keyboard, and then drag from the control to an empty space in your code file after the @interface definition:
You can drag from the Document Inspector as well, which can be helpful if you have a complicated UI with nested controls. A popover will then show, giving you the option to choose either Outlet or Action. Choose Outlet and name it ClickMeButton:
Click Connect after youve filled out the form, and Xcode will insert the appropriate code in the .h file:
Save the file, and then go back to Xamarin Studio. In the MainWindow.designer.cs file we should now see our new Outlet exposed as a property on the MainWindowController class:
Note that this is a partial class, so that Xamarin Studio doesnt have to edit our MainWindowController.cs file. As you can see, Xamarin Studio listens for changes to the .h file, and then automatically synchronizes those changes in the respective designer.cs file to expose them to your application. We need to create one more Outlet for our label, so lets switch back over to Xcode. Create the labels Outlet the same way we did the buttons Outlet and name it OutputLabel. The .h file should have the following Outlets now defined:
@property (assign) IBOutlet NSButton *ClickMeButton; @property (assign) IBOutlet NSTextField *OutputLabel;
Now that we have our Outlets wired up, lets save the files and switch back to Xamarin Studio to actually do something interesting with them. Note: It probably took a long time to create the UI and Outlets for our first application, and it may seem like a lot of work, but weve introduced a lot of new concepts and weve spent a lot of time covering new ground. Once youve practiced awhile working with IB, this interface and all its Outlets can be created in just a minute or two.
numberOfTimesClicked = 0; }
Next, in the same class (MainWindowController), we need to override the AwakeFromNib method and add some code to update our label with the number of times the button was clicked:
public override void AwakeFromNib () { base.AwakeFromNib (); ClickMeButton.Activated += (object sender, EventArgs e) => { numberOfTimesClicked++; OutputLabel.StringValue = "Clicked " + numberOfTimesClicked + " times."; }; }
We need to use AwakeFromNib, instead of another method such as Initialize, because AwakeFromNib is called after the OS has loaded the UI from the .xib file. If we tried to access the button control before the .xib file has been fully hydrated, wed get a NullReferenceException error because the button control would not be created yet. Also notice that we used the Activated event on the button. Its kind of a strange name but its the event that gets raised when the button is clicked. Thats it! Weve created our first Xamarin.Mac application, so now its time to run it and test it!
Debug A debug build is compiled into an .app (application) file with a bunch of extra metadata that allows us to debug whats happening while the application is running. Release A release build also creates an .app file, but it doesnt include debug information, so its smaller and executes faster. AppStore An AppStore build creates a signed application package that is ready to submit to the App Store.
In our case, we just want a debug build, so lets make sure that Debug|x86 is selected in the build drop down:
Then, either press +B, or from the Build menu, choose Build All. If there are no errors, youll see a Build Succeeded message in the status bar of Xamarin Studio. If there are errors, review your procedure and make sure that youve followed the steps correctly. Start by confirming that your code (both in Xcode and in Xamarin Studio) matches the code in the tutorial.
Press +Enter From the Run menu, choose Debug Click the Gear icon with the green circle from the build toolbar.
The application will build (if it hasnt been built already) and if we click the button a few times, we should see something like following:
Congrats, youve now built and run your very first Xamarin.Mac application!
Summary
Congratulations! We covered a lot of ground here, but if you followed this tutorial from start to finish, you should now have a solid understanding of the components of a Xamarin.Mac application as well as the tools used to create them. In the next guide, were going to take a look at the Model, View, Controller (MVC) pattern in Mac and how its used to create more complex applications.