XCode and MonoDevelop from a Visual Studio developer’s point of view

(This article pertains to Xcode 4 and MonoTouch 5)

Starting Mono development can be challenging on many levels. One of these levels, is wrapping your head around each platform’s different user interface design paradigms: Whereas the Visual Studio developer will be used to UserControls and MVVM templates and bindings, User Interface is done slightly different in the Xcode world, which the MonoTouch framework integrates into.

Development on Macs has been done using the Model-View-Controller pattern since the early 80s. As such, when you are developing an iOS application using MonoTouch, you are generally compositing Controllers together. In the example below, we have a mapping application that consists of three significant views: The map itself, the settings dialog and the details dialog. As such, we compose the application of three view controllers:

  • UINavigationController (more on this later)
    • MapViewController
    • SettingsViewController
    • DetailsViewController
Main/Default View of the App
Settings dialog
Details view

Each ViewController is first created in MonoTouch, whereafter its XIB-file is opened in Interface Builder (simply by double-clicking it in the project listing).

MonoDevelop - Add - New File
New File Window

Now, here is where things get scary, if you are a Visual Studio developer!

Things are getting scary ...

Being presented to us, is a sheet onto which we can define views. The UIViewController we created from MonoDeveloper has a View property, which are represented as the iPhoneish rectangle. Now, as a Visual Studio developer, you might be tempted to drop some UserControls (there’s an Objects-library-thing at the bottom right that looks like Controls), double-click them and act on their default events. Not so in Xcode. Where it is true that the Objects-library-thing at the bottom right is in fact a library, it’s a library of Views. As such, we have to work with them a little differently. Let’s start by placing a map onto our view (it’s a MapView we’re building, after all): In the bottom-right, start typing map and see how the library finds your view for you:

Click-and-drag that view onto your view until and adjust its size as needed. Having a map in its place, we can start changing its attributes. Let’s have it show the user’s current location! To get to what we would think of as the property sheet, we first click the view we would like to modify (to focus it), and then lift our gaze to the top-right of the Xcode window, where we find the Inspectors panel.

In this panel, we click on the Attributes inspector to change this particular setting:

Alright! Let’s see where we are at! Switching back to MonoDevelop, we notice how it gets busy updating itself on our changes in Xcode (progress bar in the bottom-left). After MonoDevelop has completed that process, we can continue to wire-in our new ViewController by instantiating it in our AppDelegate:

When that is done, start your app by pressing CMD and ENTER and see that it happily starts, asks for permission to track you, and then show your location on the map:

Now, since we are running in the simulator, iOS has automatically teleported us to California! Yay us! On device, however, we are left where we started. Perhaps teleporting will work in a future version.

If you compare the picture above with the one earlier in this article, you will notice a few differences. For one, we are zoomed out something fierce! Second off, we don’t have any navigation controls. Let’s work on that first issue as it introduces us to several new concepts.

To zoom in on the user’s location, we need to manipulate the map during runtime. And to do that, we need a reference to it! Again, in Visual Studio, we would presume that the map was a property of the view that we created and thus would be available via a myMapViewController.View.mapView or something similar. Here, however, to get access to our map from code, we need to create an outlet. Returning to Xcode, we click our MKMapView instance once to focus it and then open the Assistant Editor (new in Xcode 4):

This causes XCode to change into a split-view where you see your view and your ViewController’s Objective-C interface declaration at the same time.

Using this layout, we can now CTRL-drag (or right-click-drag) our MapView into our interface declaration, thus creating an outlet:

An XCode outlet will end up as an accessible property in C# once we return to MonoDevelop.

Back in MonoDevelop, open your MapViewController and navigate to its ViewDidLoad-method. Here, after the call to base, reference your map instance and – it’s just C#, baby! Subscribe to the map’s DidUpdateUserLocation-event, calculate an appropriate visible region and go:

To recap: We design our user interface in Xcode, but to get a hold of the views we are laying out, we need to create outlets, which then will make properties available in our C# code. Our solution currently looks like this:

Now, for the navigation options. Instead of loading view directly onto our window, let’s utilise a UINavigationController to … control the navigation! In our AppDelegate, replace the reference to our MapViewController with a reference to UINavigationController and instead of adding our default (or root) controller’s View to the window, simply set the window’s RootViewController:

Running our app now, produces the following result:

To add the navigation buttons, we return to XCode by double-clicking on the MapViewController.xib. We want to add some sort of button, so we filter our Object Library by button, finding Bar Button Item:

Drag two of those onto the XCode’s dock, being the gray vertical bar to the left of the design view:

In the Attributes inspector (remember? Top-right), set the title of the two buttons and customise them to your liking:

Again, to get access to the button instances from code – so we can add them to our NavigationBar (more on that later) – we will have to create outlets for them. In Xcode, show the Assistant Editor by pressing option+command+return and right-drag the two buttons to the code, generating the following snippet:

However, we are not only interested in the instances themselves, but also one of their touch events, so we’ll demonstrate adding that using Xcode as well. Right-click on the top-most button in Xcode’s dock and under Sent Actions, click-and-drag from the empty circle to the code view on the right:

Give it a friendly name (demoButtonTapped, for example), and do the exact same thing with the settings button:

Being done with the Xcode for now, we can return to MonoDevelop to wire up the buttons to the UI. In our MapViewController.cs-file, after the point where we wired-up our map’s DidUpdateUseLocation-event, add the following code to add the buttons to their navigation controller:

So far, so good. However, clicking the buttons does nothing at the moment, since we have yet to handle their events. We *could* have wired up their events as we are used to:

… but as I am sure you remember, we already created action outlets for these in Xcode, so let’s use those instead:

When we created our action outlets in Xcode, MonoDevelop automatically connected those to partial implementations which we can choose to implement ourselves. Both ways work fine.

The SettingsViewController in this case is based on the MonoDialog assembly, which you can read more of here or sit back and enjoy here.

That’s the song and dance of working with XCode!

Enjoy!

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>