MonoTouch MessageService

UIAlertView

In MonoTouch the way you ask the user simple questions is using the UIAlertView.

var alert = new UIAlertView ("Open this website in Safari?", "http://www.google.com", null, "OK", "Cancel");
alert.Clicked += (sender, buttonArgs) => 
	{
		if (buttonArgs.ButtonIndex == 0) //OK Clicked
		{ 
			UIApplication.SharedApplication.OpenUrl (new NSUrl("http://www.google.com"));
		}
		if (buttonArgs.ButtonIndex == 1) //Cancel Clicked
		{ 
			Console.WriteLine("Cancel clicked");
		}
	};
alert.Show ();

Most of the time I find myself using a standard combinations of options, OK+Cancel, Yes+No or simply OK.

I found this type of usage analogous to the MessageBox.Show method from standard .net.

MessageService

However I found the UIAlertView usage syntax a little verbose when compared to MessageBox. I would prefer a signature like this.

public static void ShowMessage(
    string title, 
    string message, 
    MessageBoxButton buttons
    Action positiveCallback, 
    Action negativeCallback)

Which would result in usage syntax like this.

MessageService.ShowMessage(
    "Open this website in Safari?", 
    "http://www.google.com",
    MessageBoxButton.YesNo,
    () => UIApplication.SharedApplication.OpenUrl (new NSUrl("http://www.google.com")),
    () => Console.WriteLine("Cancel clicked")
    );

So I built a MessageService.

public static class MessageService
{

	static NSObject nsObject;

	public static void Initialize(NSObject nsObject)
	{
		MessageService.nsObject = nsObject;
	}

	public static void ShowMessage(string title, string message, MessageBoxButton buttons, Action positiveCallback, Action negativeCallback)
	{		
		UIAlertView alert = BuildAlert(title, message, buttons);
		alert.Clicked += (sender, buttonArgs) => 
						{
							if (buttonArgs.ButtonIndex == 0) 
							{
								positiveCallback();
							}
							else
							{
								negativeCallback();
							}
						};	

		nsObject.InvokeOnMainThread(alert.Show);
	}

	public static void ShowMessage(string title, string message)
	{		
		UIAlertView alert = BuildAlert(title, message, MessageBoxButton.OK);
		nsObject.InvokeOnMainThread(alert.Show);
	}

	public static void ShowMessage(string title, string message, MessageBoxButton buttons, Action positiveCallback)
	{		
		UIAlertView alert = BuildAlert(title, message, buttons);
		alert.Clicked += (sender, buttonArgs) => 
						{
							if (buttonArgs.ButtonIndex == 0) 
							{
								positiveCallback();
							}
						};	

		nsObject.InvokeOnMainThread(alert.Show);
	}

	static UIAlertView BuildAlert(string title, string message, MessageBoxButton buttons)
	{
		switch(buttons)
		{
			case MessageBoxButton.OK :
				return new UIAlertView(title, message, null, "Ok", null);
			case MessageBoxButton.OKCancel :
				return new UIAlertView(title, message, null, "Ok", "Cancel");
			case MessageBoxButton.YesNo :
				return new UIAlertView(title, message, null, "Yes", "No");
		}
		throw new NotImplementedException(buttons.ToString());
	}	

}

public enum MessageBoxButton
{
	OK,
	OKCancel,
	YesNo,
}

But it is a Static class

Yes I know static classes are bad. They make it hard to unit tests and can contribute to spaghetti code. Well in this case I am just trying to illustrate the idea. Feel free to change it to a instance class that implements an interface. You can then inject it using your favourite IOC.

Background threads

Because in my case I may want to show a message box from a background thread I need to call NSObject.InvokeOnMainThread. This means I need an instance of NSObject. To achieve this I have an Initialize method. This should be called from your AppDelegate constructor as such.

public AppDelegate()
{
	MessageService.Initialize(this);
}
Posted by: Simon Cropp
Last revised: 09 Jun, 2012 01:03 AM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.