Brian Long Consultancy & Training Services
Ltd.
March 2011
Accompanying source files available through this
download link
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
K
builds the active project in the solution while
B
builds all projects in the solution).
Now is the time to test the application. You can run the application from MonoDevelop
with the Run menu or
(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.
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.
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.
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.
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