First MonoMac App Hits the Apple AppStore

Yvan Janssens (@yvanjanssens) just wrote to let me know that iProxify Plush, his MonoMac-powered application, has been accepted for distribution on Apple's Mac AppStore.

This is an important development in the history of MonoMac, as someone has actually published a full executable based on the tools that we built (we have not tested this ourselves as we did not really have anything to publish).

It also means that we got all the details right to let people use C# to publish to the Mac AppStore: we do not take external dependencies, we bundle all of the Mono dependencies with the app and we follow all the relevant Apple rules for distribution.

Congratulations to Yvan for his published app!

Posted on 31 Jan 2011 by Miguel de Icaza

Patterns for Creating UITableViewCells

At one point or another, every UITableView programmer will outgrow the default set of UITableViewCells styles available to them, and they will be forced to customize the cells to provide a better user experience.

The initial temptation of every lazy programmer like myself is to do the bare minimum amount of work to obtain the desired effect. This path typically starts by realizing that you can add a subview to your cell, like this:

static UIImage logo = UIImage.FromFile ("logo.png");
UITableViewCell CreateCell ()
{
	var cell = new UITableViewCell (UITableViewCellStyle.Default, "key");
	var imageView = new UIImageView (logo) {
		Frame = new RectangleF (10, 10, 20, 20);
	};
	cell.ContentView.Add (imageView);
	return cell;
}
	

Although the above code works, and you can get away with it for simple tasks, it does not take into consideration cell reuse. UITableViews like to recycle cells on the screen which is fine as long as you do not need to use a different image on each cell, as all of a sudden, you will need to keep track of the imageView value.

In other cases, your GetCell method will get bloated with a lot of inside information about all possible customizations that you might have done in a previous instance, and you will have to undo those. Apple's UICatalog sample is packed with code like that, and so is my port of the same code.

And that is just not a decent way of living.

You are miserable, your users are miserable and everyone around you is miserable.

My preferred pattern, which has worked better for me is to create a derived cell class that tracks all of my properties, and centralizes the management of updating the properties of my cell.

Assuming that my cell will render the contents of an object called "MyData", this is what my pattern looks like for custom UITableViewCells:

//
// I create a view that renders my data, as this allows me to reuse
// the data rendering outside of a UITableViewCell context as well
//
public class MyDataView : UIView {
	MyData myData;

	public MyDataView (MyData myData)
	{
		Update (myData);
	}

	// Public method, that allows the code to externally update
	// what we are rendering.   
	public void Update (MyData myData)
	{
		this.myData = myData;
		SetNeedsDisplay ();
	}
}

//
// This is the actual UITableViewCell class
//
public class MyDataCell : UITableViewCell {
	MyDataView myDataView;

	public MyDataCell (MyData myData, NSString identKey) : base (UITableViewCellStyle.Default, identKey)
	{
		// Configure your cell here: selection style, colors, properties
		myDataView = new MyDataView (myData);
		ContentView.Add (myDataView);
	}

	public override void LayoutSubviews ()
	{
		base.LayoutSubviews ();
		myDataView.Frame = ContentView.Bounds;
		myDataView.SetNeedsDisplay ();
	}

	// Called by our client code when we get new data.
	public void UpdateCell (MyData newData)
	{
		myDataView.Update (newData);
	}
}

With the above pattern implemented, I can now add all of my view specific gadgetry into the MyDataView class, images, helper labels, or other views.

Then, the Update method needs to make sure that all of those extra views are updated when this method is invoked. All of the configuration for your cell needs to take place in this method, and nowhere else.

The client code that uses these views then looks like this:

class MyTableViewDataSource : UITableViewDataSource {
	public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
	{
		MyData myData = Lookup (indexPath);

		var cell = tableView.DequeueReusableCell (key);
		if (cell == null)
			cell = new MyDataCell (myData);
		else 
			cell.UpdateCell (myData);
		return cell;
	}

The Extra UIView

You might be thinking that creating the extra UIView is not really worth the effort, as you likely only need to apply a few customizations, and you got already most of your bang for the buck by creating your custom UITableViewCell.

You would be right.

The reason for creating a custom UIView, is that there might come a time when you want to do some custom drawing in your cell. Perhaps add a nice gradient on the background, or perhaps draw some shadows, or mix large fonts with small fonts.

It might be just a couple of small touch-ups, nothing too complicated, but just a little extra polish. By using a custom UIView, you can now spice up your view just a tiny bit, by overriding the Draw method:

public override void Draw (RectangleF rect)
{
	var context = UIGraphics.GetCurrentContext ();
	UIColor.White.SetColor ();
	context.FillRect (Bounds);
	context.DrawLinearGradient (myGradient, start, end, 0);
}

Creating a MonoTouch.Dialog Element

If you are like me, lazy, you would likely not be writing a lot of GetCell methods and large dispatch tables for your UITableViews, and instead you are using MonoTouch.Dialog.

MonoTouch.Dialog is an API that takes away the administrivia out of building UITableViews and lets you focus on the content. I discussed MonoTouch.Dialog last year on my old blog.

Once you have your own UITableViewCell, it is trivial to turn that into a MonoTouch.Dialog Element. You would do it like this:

public class MyDataElement : Element {
	static NSString key = new NSString ("myDataElement");
	public MyData MyData;

	public MyDataElement (MyData myData) : base (null)
	{
		MyData = myData;
	}

	public override UITableViewCell GetCell (UITableView tv)
	{
		var cell = tv.DequeueReusableCell (key) as MyDataCell;
		if (cell == null)
			cell = new MyDataCell (MyData, key);
		else
			cell.UpdateCell (MyData);
		return cell;
	}
}

With the code above, you have everything you need to make your custom cell to be used with MonoTouch.Dialog.

You can see the entire pattern in action in TweetStation's source code. The 300 or so lines of code in that file are responsible for rendering a tweet in TweetStation.

Posted on 18 Jan 2011 by Miguel de Icaza

Mono Packager and the Apple AppStore

We are happy to announce the Mono Packager for OSX.


MonoDevelop UI for Mac Packages and Installers.

The Mono Packager for OSX makes it possible to create self-contained Mono applications that will run on OSX without requiring the Mono.framework to be previously installed on the system. In combination with the MonoMac project you can build fully native MacOS X applications using your favorite .NET technologies. From your choice of Mono/.NET languages, to your choice of Mono/.NET library.

The packager can create both signed applications for distribution on the Mac AppStore, as well as creating installers for your software.

Mono on the Mac: Some Background

Mono on OSX has historically been distributed as an image that installed itself in /Library/Frameworks/Mono.framework. Once Mono was installed, users could write code in C# or their favorite .NET/Mono language and run the resulting executable.

The problem is that Mono.framework contains an entire development stack: compilers, GUI tools, command line tools, libraries, documentation which is convenient for developers, but most of the time, not very useful for end-users.

This meant that developers would typically ask users to first install the Mono.framework (a big download) and then they could install their applications.

To work around that problem, some developers have chosen to manually embed Mono in their applications. This has always been possible, but it was error-prone as developers would have to manually assemble Mono into their application bundle, configure Mono properly, and initialize the Mono runtime themselves. Doable, but not pleasant.

With today's release, we have taken the burden of creating self-contained Mono applications out of developer's hands and added it as a standard feature for developers to use.

The Mac AppStore

The Mac AppStore requires that applications submitted to it are completely self-contained and they do not depend on third-party frameworks to be installed on the system. It also requires that your application and installer be signed.

Both of those features are supported in our MonoMac Packager. Developers can now create Mac AppStore ready applications using MonoDevelop and MonoMac. We have integrated the package creation, installer creation, and signing processes into our MonoDevelop IDE.

All that developers have to do is sign up for Apple's Mac developer program, get their distribution certificates, build a fabulous application and upload the application using the Application Loader to Apple.com.

Upcoming: Linking

In this version of the Mac bundler, we include all of the dependencies that your program takes. For example, if you use the System.Xml library, the entire System.Xml library will be bundled with the application.

In our next release, we will add support for Mono's linker, the same technology we used in MonoTouch to reduce the executable size.

When you choose to use use the linker, the granularity of distribute changes from the library-level to the type level. For example, if you only use one type from System.Xml, the linker will strip out all of the unused classes and generate a new System.Xml library that only contains the one type that you used.

We did not want to wait for the linker to be ready before shipping our packager, but we should have it ready soon.

MonoMac Refresh

As part of this release we have also issued a refresh to the MonoMac library and templates.

From now on, MonoMac binaries will default to be 4.0 profile, allowing users to leverage all of the new features in the C# 4.0 language (like dynamic) as well as the new .NET 4.0 APIs that we introduced with Mono 2.8.

The updates to the MonoMac API are described in my other blog post.

Posted on 10 Jan 2011 by Miguel de Icaza

New MonoMac Refresh!

As part of today's release of the Mono Packager for OSX we have issued a new MonoMac refresh.

As we create more sample code, and start to write real applications with MonoMac, we have updated the API to be simpler, cleaner and more comprehensive. This release is all about small incremental improvements to the MonoMac API.

As usual, we have updated the our MonoMac API documentation MonoMac API documentation. If you are thinking about getting started with MonoMac, we strongly recommend you read our MonoMac page for some useful links and tutorials.

Statistics

MonoMac 0.4 was installed by 263 developers, MonoMac 0.5 by 369 developers. Interesting considering that the holidays are a slow season:

Apps!

Frank Krueger the creator of iCircuit a real-time circuit emulator and editor for the iPad/iPhone has started a port of iCircuit to MacOS X using MonoMac:

Pretty amazing, considering that Frank only learned to use MonoMac yesterday (although he does have extensive MonoTouch experience). Update: He posted and updated screenshot "now in technicolor".

MacDoc Sample

During the holidays, I wrote MacDoc a native front-end for the MonoDoc documentation engine. I also took Jonathan Pobst's fabulous style sheets from Kipunji to spice up the UI a little bit.

This is the result:

I still have to integrate the index and search features of MonoDoc into the UI, and I am struggling as to how to surface them in the UI.

The Index is supposed to have an alphabetical listing of classes, method, properties, fields, similar to the index at the end of a book. I always found this to be very useful when developing with .NET. The search functionality on the other hand uses Lucene to search in the documentation body.

At this point, I believe that I should add a tabbed widgets, and let the user pick between the tree view on the left and the index (with a new text-entry to do the incremental search). But if the users uses the search on the toolbar, I should replace the tree and the index with a list of results.

Does the above make sense, or you think it is a terrible UI idea and completely unacceptable for OSX users?

I thought about merging the index and the body search, but it would render the index search a bit useless. Anyways, if you are a Mac expert, please send feedback my way.

Posted on 10 Jan 2011 by Miguel de Icaza

CorePlot Bindings for MonoMac and MonoTouch

Happy New Year!

Today I wrote the MonoMac and MonoTouch bindings for the open source CorePlot library.

The bindings are available from the binding collection module on GitHub and binaries for both MonoTouch and MonoMac are available there.

Posted on 01 Jan 2011 by Miguel de Icaza
This is a personal web page. Things said here do not represent the position of my employer.