Assumptions
For this tutorial I will assume that you have OS X, Mono 1.1.8.1, Cocoa#, and Apple's Developer Tools installed. I'm also assuming that you're a novice at Apple Tools and using Cocoa#. I just switched from Windows to Apple 2 months ago. I had to figure all of this out the hard way :)
Starting Off
Building The NIB
The first thing to do is create a NIB file for use with the application. A NIB file is so much easier to use than creating the entire window and controls via code.
- Go to Macintosh HD/Developer/Applications and run Interface Builder.
- Create a new Cocoa Application.
- Drag a "NSButton" and "NSTextField" from the controls windows to the empty window that is being displayed.
- In the smaller window (normally lower left) that has 5 Segments named Instances, Classes, Images, Sounds, and Nibs click on Classes.
- Scroll all the way to your left, Right Click on the "NSObject" and select "SubClass NSObject".
- Name the new object "ApplicationController".
- Right Click on "ApplicationController" and select "Instantiate ApplicationController". This will make the Instances tab of the window visible. You should now see a blue cube with the name of "ApplicationController".
- Click on the Classes tab again, find "ApplicationController", and Right Click on it, select "Add Outlet".
- This will make the Info Window visible (if it wasn't already). Add a new outlet named "textBox1", set the type to "NSTextField". Add another outlet named "mainWindow" and set type to "NSWindow". In the same window click on the "Actions" tab and add an action named "buttonClick".
- Go back to the Instances tab, hold the Ctrl key down and click on "ApplicationController" and drag to the "NSTextField". After you do this the Info window will appear (if not already visible) and will be on the Outlet's page. Make sure that you highlight the outlet named "textBox1" and then hit "Connect".
- Ctrl Click and drag from the "NSButton" to the "ApplicationController" The Info window will appear, if the "buttonClick" action is not highlighted, go ahead and highlight it and then click connect.
- Ctrl Click and drag from "File's Owner" to "ApplicationController", connect to the "delegate" Outlet.
- Ctrl Click and drag from "ApplicationController" to "Window" instance (located in Instance tab) Assign this to outlet "mainWindow".
- Ctrl Click and drag from "Window" to "ApplicationController" and assign this to outlet "delegate".
Actions vs. Outlets
Actions: Actions are like events. Creating an action in a nib will allow you to assign it to any control that has event capabilities. ''Note: You can also assign actions via code (ie "button1.action = buttonClick")''
|Actions are connected by Ctrl Clicking/Dragging from the Interface Element to the Controller Object| |:--------------------------------------------------------------------------------------------------|
Outlets: Outlets are a way to tie objects in the GUI to variables in code. If you don't have the outlet tied to anything then you can't use it. It's a way to tell the Code what variable is pointing to what interface element.
|Outlets are connected by Ctrl Clicking/Dragging from the Controller Object to the Interface Element| |:--------------------------------------------------------------------------------------------------|
The Code
Main.cs
The main.cs file is the entry point to the app. I split this off from the actual ""ApplicationController"" so that I can keep track of things easily. ``` using System; using System.Runtime.InteropServices; using Apple.Foundation; using Apple.AppKit;
class MainClass { public void Run() { Console.WriteLine ("initing: {0:x}", (int)Apple.Foundation.Class.Get("NSBundle")); Application.Init(); Console.WriteLine ("initd"); Application.LoadNib ("Main.nib"); Application.Run(); }
static void Main(string[] args) {
MainClass main = new MainClass();
main.Run();
}
} ``` The important thing to consider here is the "Application.LoadNib()" line. Make sure it's loading the proper NIB file.
ApplicationController.cs
The applicationcontroller.cs is the main interface handling point. This is where all the GUI elements are connected and defined. ``` using System; using System.IO; using System.Collections; using Apple.Foundation; using Apple.AppKit;
[Register("ApplicationController")] public class ApplicationController : NSObject {
[Connect]
public NSTextField textBox1;
[Connect]
public NSWindow mainWindow;
protected ApplicationController(System.IntPtr a, bool b) : base(a, b){}
//Form.Load Event
[Export("applicationWillFinishLaunching:")]
public void FinishLoading(NSNotification aNotification) {
textBox1.stringValue = "Form Loaded";
}
[Export("buttonClick:")]
public void buttonClick(object sender) {
textBox1.stringValue = "Button Pushed";
}
} ```
Connect/Register
I'm not sure what the technical explanation for this is, but this is the part that connects the variable you define to the object from the nib. You can have interface elements that do not have a local variable in the code, but you cannot connect local variables to non existant interface elements. Doing so will cause the app to crash on launch. For every interface element that you want to be able to access via code, you will need to create a new variable of the proper type and make sure that you use the "Connect" statement above it.
The Register statement above the beginning of the class connects this class to the "ApplicationController" from the NIB.
Export
The export tag is the one that ties local events to the events declared in the NIB. You can assign these events to an interface object a couple of ways. You can Ctrl Click and drag from the interface element to the controller class, or you can define it via code. The NIB method is normally easiest but some interface elements don't like it.
In the above example you can see that I have exported "buttonClick:" to my local buttonClick handler. The "applicationWillFinishLaunching:" event is generated by the (app/main window). Think of it like the FormLoad event in winforms (as far as I can tell).
Helper Files
I create two more files just to kinda make my life easier. I create a makefile and then a command file. I create the command file so that I don't have to keep a terminal window open all the time.
Makefile
``` all: test
test: Main.cs mcs -t:exe -out:SimpleTutorial.exe -pkg:cocoa-sharp *.cs rm -rf SimpleTutorial.app macpack -m:2 -n:SimpleTutorial -o:. -a:SimpleTutorial.exe -r:/Library/Frameworks/Mono.framework/ Versions/Current/lib/libCocoaSharpGlue.dylib -r:Main.nib ``` I don't know much about makefiles, but the important parts in this file are anywhere the name "SimpleTutorial" is mentioned. Change this to whatever you want your program to be named. The -pkg option on the mcs command makes sure that it's compiled with the cocoasharp package. MacPack is the tool that creates the app bundles for OS X. Make sure you include any nibs/images/icons/etc as a resource by using the -r option of macpack.
Command File
This will give you a file you can just double click on to run the make file. Create this file in text editor and save it as
<something>
.command ```
!/bin/tcsh
if launched from the finder, we'll not be in the correct directory.
get to the directory where this script file lives
cd dirname $0
make ```
Finished
Well, you should now be finished. Double Click on the
<somthing>
.command file and you should see everything compile successfully. If all went well you should see an OS app icon labeled SimpleTutorial. Double click on it, and you should see a new app running.
If not, or if you find an error, please send an email to binary.god@gmail.com or comment in this wiki page.