Nibless MonoMac

Many developers do enjoy the use of a visual designer when building apps.  However, there are many like myself that prefer to build GUI applications through code alone. I use this little trick for the Eto.Forms cross platform UI framework.

The problem with doing this is Cocoa (and thus MonoMac) typically requires at least one xib for your main window and menu. If you do not provide one, your application actually loads the nib for (why??), which causes problems. Thanks to some teachings from this post here, we can translate that for use in MonoMac.

Here’s a little excerpt from the Eto.Forms code that shows the magic needed to create a nibless monomac project. What this does it skip loading the nib if the filePath to the nib is empty, which is what happens when you start an app with no nib defined in NSMainNibFile.

public static class EtoBundle
	static IntPtr selEtoLoadNibNamed = Selector.GetHandle ("etoLoadNibNamed:owner:");
	static IntPtr selLoadNibNamed = Selector.GetHandle ("loadNibNamed:owner:");

	public static void Init ()
		var bundleClass = ObjCExtensions.GetMetaClass ("NSBundle");
		bundleClass.AddMethod (selEtoLoadNibNamed, new Func<IntPtr, IntPtr, IntPtr, IntPtr, bool> (EtoLoadNibNamed), "B@:@@");
		bundleClass.ExchangeMethod (selLoadNibNamed, selEtoLoadNibNamed);

	static bool EtoLoadNibNamed (IntPtr self, IntPtr sel, IntPtr filePath, IntPtr owner)
		var str = new NSString (filePath);
		if (str.Length == 0)
			return true;
		return Messaging.bool_objc_msgSend_IntPtr_IntPtr (self, selEtoLoadNibNamed, filePath, owner);

Note: This uses some code from ObjCExtensions to perform its magic, which are just wrappers to some objective-c functions.

Now you just call EtoBundle.Init() right after your NSApplication.Init(), and be sure to set your app delegate manually:

NSApplication.SharedApplication.Delegate = new MyAppDelegate ();

.. and finally, in your Info.plist, just delete the Main nib file name (NSMainNibFile).

A full working sample application can be downloaded here.