Mono

Using C# to Develop for iPhone, iPod Touch and iPad

Brian Long Consultancy & Training Services Ltd.
March 2011

Accompanying source files available through this download link

Page selection: Previous  Next

Event Handlers for CocoaTouch Actions

Switching back to MonoDevelop causes the code behind file (MainWindow.xib.designer.cs) to be regenerated so let’s take a look at it now (listed below with some unimportant lines removed for brevity). What we have here in the code behind file is a partial class definition for the AppDelegate class that is also partly declared in Main.cs file. A MonoTouch attribute has been used to ensure this Mono class is bound to the Objective-C AppDelegate class down at the CocoaTouch level.

You can see a declaration for the event handler method myButtonPressed() is there, with another attribute to bind it to the Objective-C action. Note the partial keyword that allows the declaration to be left here without an implementation. We will implement the method in Main.cs. The rest of the class consists of the properties that represent the outlets (along with setters, getters and private variables in the real code) along with yet more binding attributes.

[MonoTouch.Foundation.Register("AppDelegate")]
public partial class AppDelegate
{
    [MonoTouch.Foundation.Export("myButtonPressed:")]
    partial void myButtonPressed (MonoTouch.UIKit.UIButton sender);
 
    [MonoTouch.Foundation.Connect("window")]
    private MonoTouch.UIKit.UIWindow window {
        get { ... }
        set { ... }
    }
 
    [MonoTouch.Foundation.Connect("myButton")]
    private MonoTouch.UIKit.UIButton myButton {
        get { ... }
        set { ... }
    }
 
    [MonoTouch.Foundation.Connect("myLabel")]
    private MonoTouch.UIKit.UILabel myLabel {
        get { ... }
        set { ... }
    }
 
    [MonoTouch.Foundation.Connect("myTextBox")]
    private MonoTouch.UIKit.UITextField myTextBox {
        get { ... }
        set { ... }
    }
}

Switching over to Main.cs we need to add in the implementation of the event handler in this partial class:

partial void myButtonPressed (MonoTouch.UIKit.UIButton sender)
{
    myLabel.Text = "Hello world! Erm, I mean Hello " + myTextBox.Text + "!";
}

Straightforwardly the code looks like regular C# code. You can check the project builds using the options on the Build menu (also CommandK builds the active project in the solution while CommandB builds all projects in the solution).

iPhone Simulator

Hello World running in the iPhone Simulator

Now is the time to test the application. You can run the application from MonoDevelop with the Run menu or OptionCommandEnter (that’s Option-Command-Enter, or Alt-Apple-Enter for those new to the Mac keyboard) and it will be launched in the iPhone Simulator. You can interact with the application using the mouse instead of your finger. If you were implementing multi-touch you can mimic two finger touches by holding down the Option (Alt) key.

Note: The iPhone Simulator is a simulator, not an emulator. As a consequence you are running regular Intel code, not ARM code, and for this and various other reasons the performance and behavior of your application may be very different than when deployed on a real device.

When you tap the text field a keyboard obligingly pops up with a highlighted button inviting you to press Done when you have entered your name. Unfortunately nothing yet happens when you press it – that’s something we have to take responsibility for. However the Touch me button works fine.

We should add in some initialization code to blank out the greeting label on startup (or clear it in Interface Builder). We’ll also alter the caption of the button (just add a character on the end, to show we can do it) and deal with this keyboard. All this code is going in the overridden FinishedLaunching() method. The call to window.MakeKeyAndVisible() is where the screen is told to display so the startup code will be placed just before that. Clearing the label is trivial but the button caption (or title) is a little more obscure. It turns out that you need to get the current ‘normal state’ title and then separately set an updated ‘normal state’ title.

myLabel.Text = "";
myButton.SetTitle(myButton.Title(UIControlState.Normal) + "!", UIControlState.Normal);

Sometimes you need to browse through the Code Completion window to see which methods or properties are available. Sometimes you need to trawl through the MonoTouch documentation (a pretty good work in progress). Sometimes you need to go back to the real documentation for CocoaTouch on the Apple web site. The syntax will look a little odd at times, but it’s all about methods, properties and so on, so acting as a reference it’s still invaluable when required.

One thing before moving on; if you tried to set the iPhone status bar to be opaque black in Interface Builder you will have noticed that the simulator ignored that setting, unlike the screenshot to the left. This can be overcome by setting it in code instead. In the same FinishedLaunching() method add this code in towards the top:

UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.BlackOpaque;

Note: UIApplication.SharedApplication is how you access the underlying Application object from anywhere in your code.

Text Entry Keyboards

As mentioned we need to tell the text field to close the keyboard when we decide it is necessary. But how do we find out how to deal with this? Well, just searching the Internet is a good start as there is quite a large amount of information on common problems that stump MonoTouch programmers and of course even more for CocoaTouch programmers. But let’s walk through a search of the documentation for how to find the answer and for the sake of it we’ll start with Apple’s reference site.

Using the Documentation

At http://developer.apple.com/library/ios you will find a list of all the iOS frameworks (CocoaTouch is an umbrella term for a few of them). The class we are looking at is UITextField and the prefix letters tell us it is part of the UIKit framework, so clicking on UIKit gives a whole list of potential reference topics to choose from including UITextField Class Reference. Clicking on that gives a big, detailed reference page, but in the Overview section it says:

"A text field object supports the use of a delegate object to handle editing-related notifications. You can use this delegate to customize the editing behavior of the control and provide guidance for when certain actions should occur. For more information on the methods supported by the delegate, see the UITextFieldDelegate protocol."

We’ll need to follow the link as we are looking for an editing-related thing that we want to customize. Typically the MonoTouch layer will merge this type of optional delegate object functionality into the main object in question, so the methods of UITextFieldDelegate will be implemented in MonoTouch’s UITextField object as delegate properties to save you the chore of building a delegate class to customize the text field object. However the delegate class is still available as an option if you want to use a separate delegate object.

The UITextFieldDelegate page describes the methods (or messages as they are called in Objective-C) supported by the delegate. If you browse the information you’ll see the message textFieldShouldreturn: is the one.

Now let’s have a look at the MonoTouch version of this. At http://www.go-mono.com/docs start expanding the reference tree along this node path: MonoTouch Framework, MonoTouch.UIKit, UITextFieldDelegate Class, Methods. Of the methods listed the one we need is called ShouldReturn – as you see, MonoTouch also simplifies some member names. Select this method and the page tells you that the method signature is a function that takes a UITextField and returns a Boolean indicating if the keyboard should do its default behavior when Return (or Done) is pressed.

So this shows the Apple and MonoTouch documentation of the same delegate object property, but as mentioned MonoTouch absorbs the delegate object into the text field. Check the help for the UITextField Class and you’ll find a ShouldReturn property that can reference a method and this is what we’ll use.

The help indicates that we can assign a regular method to this property (with the right signature), but it also says an anonymous method can be used. Anonymous methods are convenient as they save a bit of typing. If the functionality is not excessive and not required elsewhere an anonymous method is a sensible option. We can also potentially reduce typing a little further by using a lambda but before worrying about what that is let’s consider what the ShouldReturn functionality needs to in order to dismiss the keyboard.

First Responders

The closest iOS equivalent to a focused control that receives input in Windows is a first responder. When you tap the text field it becomes first responder and displays the keyboard. Dismissing the keyboard is simply a matter of dropping this first responder state.

myTextBox.ShouldReturn = delegate(UITextField textField) { return textField.ResignFirstResponder(); };

ResignFirstResponder() returns true if its first responder status was lost and so this value is returned from the anonymous method, meaning the text field should process the press of Return. The anonymous method above could be laid out to look more like a traditional method implementation, but there is no real need or benefit. It can also be compressed a little and turned into a lambda:

myTextBox.ShouldReturn = textField => { return textField.ResignFirstResponder(); };

The body of the lambda contains a statement so the braces are required. However if the body is an expression whose type is the same as the target function return type we can simplify even further (the outer parentheses are just for clarity and can also be removed if preferred).

myTextBox.ShouldReturn = (textField => textField.ResignFirstResponder());

All three options are identical in meaning, although you’ll notice that explicit parameter type information was removed in the lambda – the compiler is able to work this out through the type of the delegate property on the left hand side.

Event Handlers for MonoTouch Events

Just before re-launching the application in the simulator to check it works let’s add in another event handler. You may recall from earlier that there were 2 ways of setting up event handlers for UI controls and we looked at the approach that used actions. We’ll add another event handler onto the same Touch me button, but this time solely in code, just using the event of the text field object.

private void InfoAlert (string msg)
{
    using (UIAlertView av = new UIAlertView("Info", msg, null, "OK", null))
    {
        av.Show();
    }
}
...
    myButton.TouchUpInside += (s, e) => { InfoAlert(
            "Hello " + myTextBox.Text); };

So event handlers (which, of course, are multi-casting in both .NET and Mono) can be added using the += operator in conjunction with a method, anonymous or otherwise. This event handler pops up an alert (the closest equivalent of a message box) via a UIAlertView object.

Note: the using statement, as you may well be aware, is an abbreviated way of ensuring that Dispose() is called, to free up the Objective-C resources when we know we are done with them. The above method is exactly the same as this slightly longer version.

private void InfoAlert (string msg)
{
    UIAlertView av = new UIAlertView("Info", msg, null, "OK", null);
    try
    {
        av.Show();
    }
    finally
    {
        av.Dispose();
    }            
}

Note: Objective-C typically requires explicit memory management, much like regular old-school Win32 programming. Mono and .NET, however, have a garbage collector (GC) and so tidy up after you. You can merrily create your objects and leave them for the GC to collect when it gets round to it, but if you want to be more responsible with the limited memory on the device you can call the Dispose() method on any objects you know are no longer required. This will cause the underlying Objective-C object to be released.

If you test the application it now behaves more as expected. The keyboard’s Done button operates and the button now does 2 things (updates the label and pops up an alert). Interestingly, pressing the button does not dismiss the keyboard, as the text box remains the first responder. You can ‘fix’ this by adding this condition into one of the button’s event handlers.

if (myTextBox.IsFirstResponder)
    myTextBox.ResignFirstResponder();

Go back to the top of this page

Go back to start of this article

Previous page

Next page