Published: 16 Dec 2009
By: Manfred Pohler
Download Sample Code

This article shows how to use MonoTouch to build an iPhone application with some common features.

Contents [hide]

The Idea behind

As a dedicated .NET developer I don't want to mess around with "Objective-C" and so MonoTouch is the right thing for me. It allows to develop iPhone applications using .NET with C#.

The problems I stumbled upon when starting iPhone development (which I did in "Objective-C" - OC from now on) was that there are many samples for OC and that a lot of things work "out of the box". Switching to MonoTouch had two effects for me. The negative: OC Samples have to be recoded and things are somehow different. The positive: back in C# I could use my existing .NET skills. .NET is different than OC - so things have to be done in the .NET way.

The sample - and what's missing

This sample is based on an existing project (Section Control) which I built during the last week. It lacks great Design and extensive error handling.

In this sample I'll show three common things. First the use of a navigation controller, second the support for portrait / landscape modes and last but not least, "Dialog handling".

Contents of the sample:

  • The use of a navigation controller, a very common thing - often needed
  • Rearrangement of views and their content
  • Simulation of Dialog behavior
  • Lots of .NET things (Events, inheritance, ...)
  • XIB Files

I like UI designers - but of course everything could be done in code also.

The "project"

Our project will have 2 screens, one for "Settings" and one main application view.

Parts of the sample

The Main View

The page has 3 "sections". Each of it is a view which will show different content from the same data.

Think of it as something like a contact detail view where one shows "Global information" (Name, Gender, ...) while another part shows communication elements (Phone numbers, email addresses, ...) and the last one shows the address (City, Street, ...).

The trick with those three parts is to rearrange them when the device orientation changes between landscape and portrait. The result should look something like this:

Figure 1: Main View in Portrait and Landscape

Main View 

in Portrait and Landscape

NOTE

We will not build such a complex thing of course. These are screenshots of my Section Control application. But the concepts and technologies are the same.

The Content Views

These three guys will be placed in the Main View. While two of them are pretty simple - one will be divided in two "regions" so we can change the layout easily.

The Settings (Options) View

Also a very common thing - we will use this to show how navigation works and how we can transfer data between the views. Normally such a view would be some kind of a table view - but in our case we will use a static view, just to keep the things simple.

The Data

To make things easy we will use a Point of Interest (POI). The data looks like this:

We have three properties, exactly the same as the number of our views.

Let's start

First we will create a new MonoTouch iPhone application. Chosse File/New/Project which brings up the following dialog:

Figure 2: The new project dialog

The new project dialog

Use the settings (choices) as shown in the image above and MonoTouch will create the following solution.

Figure 3: The newly created project

The newly created 

project

We will later create code - first let's add all the elements to the project and do some design work. As I wrote before we'll use XIB files to have a UI designer. MonoTouch offers a project element for this. Right click on you solution in solution Explorer and choose "Add / New File".

Figure 4: Add a new View Controller

Add a new View 

Controller

Repeat this step and create: VCMainView, VCInnerViewComplex, VCOptionsView.

Next let's add four simple class files: OurNaviController, BaseInner, BaseComplexInner and OurData.

Figure 5: Add standard files (Classes, Interfaces, ...)

Add 

standard files (Classes, Interfaces, ...)

Figure 6: The final look of the project

The final look of the 

project

Notice: IDataHolder is not used in this article!

Now we have all the classes needed to complete our project. Before we go on I'll explain some concepts - well known by iPhone developers - but maybe new for .NET guys like me.

The graphic shows the data for USA at the moment. And on the left side we can make a choice between Europe, USA and Asia.

iPhone basics - XIB files

XIB files are something like the xxx.designer.cs files for Windows Forms applications. MonoTouch parses these files and creates code for us. And here is the first difference. In Windows Forms we create a control and give it an ID. With XIB we use something called "outlets". This is somehow different, but you'll get used to it.

XIB files are use by an application called "Interface Builder". Just double click a XIB in MonoTouch to open the file in this program.

The general handling: you select a class (most of the time the one behind "File's Owner") normally the one which is the UIController. For an example VCMainView is the class we are using when defining "outlets" for our controls in the VCMainView XIB.

The steps to create an "outlet" and bind it to a control:

  • Drag the control to the surface (don't care about the name)
  • Select "Classes" from the Library window
  • Select your "Files Owner Class" (VCMainView in this case)
  • Select "Outlets" from the class detail view
  • Click the plus sign below the list and add an "ID" for your control
  • OPTIONAL - choose the correct class for your outlet

Repeat those steps for all controls you want to reference from code. Of course it is easier to first drag all controls to the view, arrange them and so forth and after this add all the outlets.

Anyhow - you have your controls, you have your outlets - now we have to assign them.

  • In the document window select the "File's Owner"
  • From the Tools menu chose "Connections". There you'll see your outlets with something like a "Radio button" on the right side
  • Click on the "Radio button" and drag it to your control (where the outlet should be connected to). Tip - if you can't reach the control on your view window (maybe it's behind another control) drag the line to the element in the Document Window.
  • Drag the lines (connect) all outlets with your controls.

After saving your file you'll have access to the "outlets" in your code, just like controls in Windows Forms applications.

There are some "get started videos" on the apple developer portal which show how this is done in "Interface Builder". If you couldn't follow the above explanations - just watch such a video.

iPhone basics - Forms...

There is no "Forms" concept on iPhone. Instead we use Views - and View-Controllers. And since we have no "multiple windows UI" there is also nothing like Form.Show() or Form.ShowDialog().

If you build a normal (games are different) application for the iPhone you'll follow a pattern called MVC.

If MVC is something new for you - please use your favorite search engine for closer information.

A View-Controller (UIViewController) normally owns a view (or some views) and controls it. It uses the view to display data and acts as a layer between his view(s) and other controllers "above".

There are special controllers like the Navigation Controller which provide special functionality. We will us such a Navigation Controller to display our different "Forms", which are UIViewControllers.

You will always see one View (Controller) at a time, there are no "Dialogs" and the things are asynchronous.

So that's the point where things become a bit different.

To display something like a dialog (in our case the Options) you either exchange the current view (controller) or (more common) use a Navigation Controller.

Since there is no Dialog (blocking the caller) functionality we have to add some kind of notification when the "Dialog" gets closed. Since we have a .NET environment this is not to difficult - we simply implement an event in our Options class and before we show the "Dialog" we subscribe to this event.

Let's build the interfaces

Before we get started one note - normally I would name the controls similar (So the Title-Label is always called lblTitle for example). In this case I use different names - just to show that there is a separation between the UI Elements and the data binding logic.

NOTE

I do this in the complex inner view. Enhancement: change the label to a text-field and the hyperlink will work!

The Main View

This view will hold three sub-views. And to see what's going on we will first create them with different colors. Later we will place our inner views there.

Double click VCMainView.xib in MonoTouch which starts Interface Builder. Drag one "UIView" from the library to your view. Size it to 290 x 135. After it hast the correct size copy and paste it. Place it to the next position. Use copy and paste again to create the third view. Change the color of the views and finally the things should look like below.

Figure 7: Main View Design

Main View Design

Also create three outlets as shown on the screenshot and don't forget to connect them with "File's Owner". Save the file and go back to MonoTouch.

The Inner View

To create the inner views we have to manage something in Interface Builder. The inner views will be the same size as the three parts in the main view. But unfortunately you can't change the view in Interface Builder to this size. The reason - IB thinks you have a Status bar.

Double Click VCInnerViewSimple.xib in MonoTouch. In IB choose Tools / Attributes Inspector and set "Status Bar" to None. After this choose Tools / Size Inspector and change the size to 290 x 135.

Figure 8: View without Status bar

View without Status 

bar

Now create three Labels - place them like you want and create outlets for the "small ones" like in the screenshot below. Don't forget to connect them. The text for the first label will show us the element we use; this is static and therefore we need no outlet for it. The other labels will be used to display data.

Figure 9: Simple Inner View

Simple Inner View

The Complex Inner View

Like with the view before we set status bar to none and change the size to 290 x 135. Instead of placing the labels on the view we place two UIView elements first (I colored them to make them better visible) and then we place the labels on these first "sub view" and a button on the second. We add outlets for the 2 views for the data labels and for the button. Again I added some static text. The result should look like in the screenshot below.

Figure 10: Complex Inner View

Complex Inner View

So almost every XIB is handled - there is one left - our main window.

The Main Window

This one is a little bit different. It will hold our navigation controller - but first let it just hold a default navigation controller. To add such a thing we choose a Navigation Controller from the Object in the library. (One of these golden circle elements). You can't drop it on the view (window) itself. Instead you must drag it to the document window. This will add a lot of elements. A Navigation Controller, a navigation bar, a View Controller and a navigation item. Don't worry - we get what we need.

Since we will not display a navigation bar (at the moment) we select navigation controller and in the attributes we uncheck the Shows Navigation Bar checkbox. Notice that I change the background color of the window!

IMPORTANT

This time we do not use File's Owner to create our delegates. Instead we use App Delegate.

Figure 11: Main Window

Main Window

There is one step left - change the class of the "Root View Controller" to our VCMainView.

Figure 12: Set VCMainView

Set VCMainView

The Settings / Options view

This final view will be simple - and it will have one special thing - a navigation item with two buttons.

One Done button and one Cancel button. To do this we first drag a navigation item to the view. A Navigation item has to be dragged to the document window (like the navigation controller before). Next drag a "Bar button item" to the Navigation Item and a second one somewhere on the document window. Set the style of the one inside the navigation item to "Done" and give it the text Done (or OK if you like).

IMPORTANT

Now we have to assign the buttons to the Navigation Item. Mark the Navigation Item and from Connections assign them like in the screenshot below. (One should already be assigned).

Figure 13: Navigation Buttons in the Bar

Navigation 

Buttons in the Bar

Finally add labels and a switch to the view. Create the following outlets.

IMPORTANT

NavigationItem must be exactly written as seen in the screenshot!

Figure 14: Options View

Options View

Notice the two labels (upper and normal case) at (almost) the same location.

Next we also add outlets to the Bar-Buttons (Cancle / Done) and connect them.

Time to code

All design is done - it's time to code. First we will do one easy thing - add a simple handling to the Cancel and Done buttons in our options.

Open VCOptionsView.xib.cs and add the following code:

This enables us to "close the dialog". Or in iPhone Language - to show the options the view controller is pushed in the navigation controller - and can be removed / closed (back to previous screen) via pop.

At the moment we don't care about Done / Cancel differences.

Next we have to show something. We'll do it (for this time) the easy way. First we add our navigation controller (the default one) to our window and then we open the "Options Dialog".

Open Main.cs and add the following code:

Now you can run the sample in the simulator and you should get the options (nasty looking) and if you click on Done or Cancel you will see the three colored "inner views" on our main view.

There is a (disturbing) nhavigation bar on top of the main view. If you comment out the push of the "Options Dialog" and run again you will see that there is no bar.

The reason is that we made this bar visible in the Options View

So we have to find a way to reverse this effect. Open VCMainView.xib.cs and add the following code.

ViewDidLoad and ViewDidAppear

ViewDidLoad gets called when the view finished loading - this is done once in the program lifecycle. ViewDidAppear is always called when the view comes into view.

So the ones of you who is carefully reading has found a first bug in our application.

We set the Navigation Bar to visible in the ViewDidLoad of our Options View. And yes - this would mean that on a subsequent call the bar will no longer be visible. So we also have to add a handler in our VCOptionsView.xib.cs to do this. The two handlers will then look like this:

Now we only have to add our "Sub Views" to the Main View elements and we have all done what we can do without doing "inheritance stuff".

Let's do this - open VCMainView.xib.cs and add the following code.

If we run our application again we will see the three guys in there. Now let's add some data.

The Data

We will have some kind of POI. And we have 3 views for it. The (self made) problem - two of them are the same class - but should display different data. There are several ways to manage this - one could be a controller one level above the views telling them what to display. The other could be the views controllers itself knowing what they should display. This seems to be OK for the two classes Simple and Complex View.

And I'll use this approach (I don't say it's the best solution) to show some possible techniques.

But let's first define the data - enter the following code to OurData.cs:

Data Display in the views

As you may have noticed from the design of our Options View we plan to display the Data Labels either normal or in upper case. Who handles this? I say the Main View acts with Options and so it will tell its sub views how they should display the data.

And since only the Main View knows when the options did change our sub views must provide a method that "redraws" the data if something changes. To demonstrate "two way communications" I not pass the "is upper case" information to the sub views. Instead they will "ask" their main view about it.

We are already prepared to extend our sub views. Let's start with the general things - the class BaseInner.cs.

This class works for all three of the sub views. As I wrote before we need a method to "Refresh" the display and we also need a back link to the main view. And we need a property for the data.

First change the code in BaseInner.cs to:

Notice - the using MonoTouch.UIKit needed for UIViewController. We need to derive from that class since our "inner views" are some kind of UIViewControllers. And also notice the abstract member RefreshDisplay. Next change the base class in VCInnerViewSimple complex to be inherited from BaseInner. This includes the implementation of RefreshDisplay - but we won't do much at the moment.

We don't need the Initialize function provided by the template. And we also have no need for the constructors with parameters. Instead we want to ensure that our Main View is set when we are constructed. So we remove the Initialize as well as the first two constructors. And we will change the third constructor to require a VCMainView as parameter. And we need the base constructor UIViewController(string nibName, NSBundle bundle) in our base class. Since bundle will (in our case) always be null we don't pass this parameter. Instead we create the following constructor in BaseInner.cs

And our VCInnerView class will finally look like this:

The only thing left is a change to the sub view construction code in VCMainView. Doing this we will also implement a method telling if the data label should be upper case. And of course we need options (normally a class - here simple a Boolean) and data.

This would work fine so far. But how can the two instances of VCInnerViewSimple know what they should display? No problem - we simply implement an integer (normally an enum would be better) to decide what they should display.

Change BaseInner.cs to:

The change to the constructor means that we have to change VCInnerView again. And we are now able to implement RefreshDisplay.

Change VCInnerViewSimple to:

Notice I also added code to display initial data.

Now change the construction in VCMainView to:

At this point you should be able to run the project and see data in the two upper sub views.

The Complex View

The main difference between simple and complex inner views is the fact that the complex one has to do some "rearrange" operations when we change the device orientation.

But except to this it is the same as a simple inner view. So we will first change our base class to be a kind of BaseInner add the RearangeForOrientationChange and the constructor with the three parameters.

Our BaseComplexInner.cs should look like this:

The implementation in VCInnerViewComplex.xib.cs should look like this:

NOTE

I know that the MainView assignment could also be done in BaseInner. I left it just to do something different.

Last not Least we have to change the construction in VCMainView.xib.cs:

Displaying Options with the button

At the moment we still push our option when the application starts. As you may have predicted by the interface design we want to do this from our Settings button in the Main view. So let's first remove the code from Main.cs (I simply comment it out with //####):

If we now start our applications it will show the main view. To bring up our options we have to add code to our button click event (in VCInnerViewComplex).

One important thing - memory is an expensive resource, especially on hand held devices. So we will not construct (load) our options until we need it. Maybe we have (expect this as standard) application runs where options will never be opened.

Our first problem - the option (I decided) will be handled by VCMainView - but the button is on VCInnerViewComplex. Let's do it the .NET way - fire an event, when the button is clicked. For this I change VCInnerViewComplex to:

Further we already know that we want to be informed on "Done" and on "Cancel" on our "Options Dialog". And we need access to the Boolean (Setting). Let's change VCOptionsView to:

Very straightforward I would say. One thing to notice - with more complex data we would create a temporary object copy the data to it and the view would then change this object. When the user clicks Done we transfer the modified data back to the original. So the caller must not take care about some kind of undo.

Now we have to handle the options in our Main View. Here are the changes to VCMainView.xib.cs:

If you run the application now it almost does what we expect it to do. But the Options look a bit bad because of the "Example" (normal or upper case). Let's fix this:

Now we can run our application and it should do all we want it to do. There is only one little thing left. If you use "Hardware / Turn right" from the iPhone-Simulator menu the device turns - but our UI does nothing!

Orientation changes

Enabling Orientation changes in an iPhone application is very easy. The system uses a mechanism which "asks" the ViewController if it should change the view or not. That is the place where the class OurNavigationController enters the scene.

NOTE

The main reason to implement our own navigation controller is not part of this article. It's about handling our own animation when switching between views. I'll handle this in another article.

We will implement our own Navigation Controller - and it is easy. One thing we have to do for MonoTouch is that we implement some constructors and "register" the class so that it can be used in XIBs too. The final code for OurNaviController looks like this:

That is the functional class - we have (a last time) to enter the Interface Designer and make a change. Double Click MainWindow.xib and change the Class of our Navigation Controller to OurNavi...

Figure 15: Assign our own Navigation Controller

Assign 

our own Navigation Controller

Now run the project again and turn the device (simulator) to landscape. Our view rotates!

You can also try this with the Options Dialog visible - it works! And the Options) look correct since it only covers about half of the landscape screen height which fits also in landscape mode. The problem is our MainView.

Let me explain what has to be done:

Figure 16: View rearrangements

View rearrangements

The light blue frame is our space for landscape mode. So we have to arrange two different things. First the lower view (white rectangle) has to change position and size. Since this is a sub view of the Main View we will do this there. Next (the blue arrow) the content of this view has to be rearranged. Since the Main View has no deeper knowledge about this the sub view will do this itself.

The movement of the view needs some position and sizes. One for landscape and one for portrait mode; portrait mode is easy - it is the size and position we get at startup. Landscape is easy to calculate. Position Y is the same as for the first sub view - position X is 2 times position X of the first sub view (I assume the distance between the two sub views is the same as from window border to the first frame).

Size landscape width is half of portrait width and height is double.

iPhone tells us when it changed orientation - we handle this in the main view. For the sub view (just to show a different approach) we use a method (RearangeForOrientationChange) call.

NOTE

A method call instead of directly handling the event can also be useful for complex animations.

So let's change VCMainView.xib.cs:

When we run after this code change a rotation will bring this result:

Figure 17: Landscape Main View

Landscape Main View

This screenshot shows why I use so many colors. It enables us to see, that the "holder" in the main view change its size, that the sub view changed its position with the parent. Only rearrangement of the Complex View is left to have a good result!

So let's change VCInnViewComplex.xib.cs:

Figure 18: Final Landscape

Final Landscape

Animation

This article will not cover animation in depth. But to better visualize the orientation changes and further to give you some idea how easy UI Animation can be we will add a last few lines of code to VCMainView.xib.cs:

Anything left?

Yes - (de-)serialization of Data / Options, Push / Pop Animation,... I'll probably write a second part of this article which will contains this stuff. I hope you enjoyed my sample

References

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Manfred Pohler

Sorry, no bio is available

This author has published 5 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Android for .NET Developers - Location and Maps
In Windows Phone and iOS getting the current position of the device in terms of latitude and longitu...
Android for .NET Developers - Using Web Views
In this article, I'll show a native app that contains a web-based view. The great news is that HTML ...
Android for .NET Developers - Building a Twitter Client
In this article, I'll discuss the features and capabilities required by an Android application to ta...
Developing a Hello World Java Application and Deploying it in Windows Azure - Part II
In this article we will see the steps involved in deploying the WAR created in the first part of thi...
Ref and Out (The Inside Story)
Knowing the power of ref and out, a developer will certainly make full use of this feature of parame...
Top
 
 
 

Please login to rate or to leave a comment.