ModalViewController (loginView) – iTrade

Most application would like the trader to log in before performing any action.  In the iTrade app I would like the trader to log in first and then proceed with trading.  For the trader to log in first, its necessary that the login screen be displayed before any other view.  To achieve this I used “PresentModalView” property on the navigation controller.

I have been fighting with this since last night and here is an additional tip that I learnt on the way

Get the hell out of AppDelegate as soon as possible

If you are coming from windows forms development, you might think its as simple as display a login form and validating the credentials.  Although it indeed is as simple as that, the important point is where to call the PresentModalView controller.  Initially I thought I would have to present it in the AppDelegate.Finished Launching. But that’s not the case.  I need to add it to the RootViewController of the navigation controller.

Add a new Controller With A View to your solution and call it “LoginContoller”.  Add fields for user name and password, and add your logic for validation.  In my case, I am using a web service to validate the login (more on this later).  Ofcourse, set the connections to your buttons and text fields in InterfaceBuilder and in your code, add an event OnLogin.  I use this event to indicate to the RootViewContoller that Login is successful.  This is how my login controller looks like:

using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using iTrade.TradingServices;

namespace iTrade
{
	public partial class LoginController : UIViewController
	{
		#region Constructors

		// The IntPtr and initWithCoder constructors are required for controllers that need
		// to be able to be created from a xib rather than from managed code

		public LoginController (IntPtr handle) : base(handle)
		{
			Initialize ();

		}

		[Export("initWithCoder:")]
		public LoginController (NSCoder coder) : base(coder)
		{
			Initialize ();
		}

		public LoginController () : base("LoginController", null)
		{
			Initialize ();

		}

		void Initialize ()
		{
		}

		#endregion

		TradingService client;
		public event EventHandler OnLogonSuccessful;
		public override void ViewDidLoad ()
		{
			base.ViewDidLoad ();
			btnLogin.TouchUpInside += HandleBtnLoginTouchUpInside;
			client = new TradingService();
		}

		void HandleBtnLoginTouchUpInside (object sender, EventArgs e)
		{
			activityIndicator.StartAnimating();
			client.BeginLogin("","", LoginCompletedEventHandler, true);

		}
		void LoginCompletedEventHandler(IAsyncResult result)
		{
			var answer = client.EndLogin(result);
			ApplicationData.IsLoggedIn = answer;
			InvokeOnMainThread( () =>
			                   {
				activityIndicator.StopAnimating();
				if(answer)
				{
					using(UIAlertView av = new UIAlertView("Logged IN", "You are now logged in ", null, "OK",null))
					{
						av.Show();
					}
					OnLogonSuccessful(this, new EventArgs());
				}
				else
				{
					using(UIAlertView av = new UIAlertView("Logged IN", "You are not logged in ", null, "OK",null))
					{
						av.Show();
					}
				}

			});

		}

	}
}

Back in your RootViewContoller, you need to create an object of LoginViewController and present it using the rootview’s navigation controller.  For the login view to be displayed correctly, you need to override the ViewWillLoad method in your RootViewController.  Create an object of type LoginController and delegate the OnLogin event to a method. This is where we will call PresentModalViewController

                void OnSuccessfulLogon (object sender, EventArgs e)
		{
			this.NavigationController.DismissModalViewControllerAnimated(true);
		}

		public override void ViewWillAppear (bool animated)
		{
			base.ViewWillAppear (animated);
			if (!ApplicationData.IsLoggedIn)
			{
				var lc = new LoginController();
				lc.OnLogonSuccessful += OnSuccessfulLogon;
				this.NavigationController.PresentModalViewController(lc, true);
			}
		}

Notice in the OnSuccessFulLogOn I dismiss the ModalViewController.

Advertisements

My First IPhone App – iTrade

Idea:  Build an app that allows the traders to update their positions while not around a computer.  For example, a trader who is sitting on a train when the Greek riots broke out, should be able to see the news and immediately be able to close out his / her positions.

Design (0.1)

– Login screen
– Display traders positions
– Display news (RSS) feeds
– Allow the trader to update his position
– Use web services for trade communications.

I started with an Ipad application just because further down the road, I would like to add a few more things like charts which require a lot of real estate.

NAVIGATION SCREEN

Navigation Screen has 2 rows – Trade Row and News Feed row.
I started with a standard ipad solution – IPad Windows Based Project. Next in monotouch solution double click on MainWindow.xib to open it in InterfaceBuilder. Drag a NavigationController in “main window”. Expand the “NavigationController” to see the “RootViewController”. We will come to this later. Save your interface builder and in your MonoTouch solution, main.cs would look like this.

#Main.cs

using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace iTrade
{
	public class Application
	{
		static void Main (string[] args)
		{
			UIApplication.Main (args);
		}
	}

	// The name AppDelegate is referenced in the MainWindow.xib file.
	public partial class AppDelegate : UIApplicationDelegate
	{
		// This method is invoked when the application has loaded its UI and its ready to run
		public override bool FinishedLaunching (UIApplication app, NSDictionary options)
		{
			ApplicationData.IsLoggedIn = false;
			// If you have defined a view, add it here:
			window.AddSubview (navigationController.View);
			window.MakeKeyAndVisible ();

			return true;
		}

	}
}

RootViewController
In your solution, add a new “Controller with a View” for IPad and name it “RootViewController”. Click your MainWindow.xib again and in the identity window – set the class to “RootViewController” – the one that you just added and save it. Back to your MonoTouch solution, double click “RootViewController.xib” and add a UITableView in InterfaceBuilder. You can set the properties to however you want the initial trade screen to look like. I have my style set to grouped. Next your UITableView needs a TableSource. Add a plain class and call it “RootDataSource”. This class needs to derive from UITableViewSource, so that its object can be a table source for the root table. Here is how the RootDataSource class looks like.

using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace iTrade
{
	enum SECTIONS
	{
		TRADER,
		MAX,

	}
	enum TRADER_ROW
	{
		TRADE,
		NEWS,
		MAX
	}
	enum LOGIN_ROW
	{
		LOGIN,
		MAX
	}

	public class RootDataSource : UITableViewSource
	{
		RootViewController _controller;
		public RootDataSource (RootViewController controller)
		{
			_controller = controller;
		}

		public override int RowsInSection (UITableView tableView, int section)
		{
			switch (section)
			{
			case (int)SECTIONS.TRADER:
				return (int)TRADER_ROW.MAX;
			default:
				return 0;
			}
		}

		public override int NumberOfSections (UITableView tableView)
		{
			Console.Write("ApplicationData.IsLoggedIn: " + (ApplicationData.IsLoggedIn ? "True" : "False"));
			if(ApplicationData.IsLoggedIn)
				 return (int)SECTIONS.MAX -1;
			else
				return (int) SECTIONS.MAX;
		}
		public override string TitleForHeader (UITableView tableView, int section)
		{
			switch(section)
			{
			case (int)SECTIONS.TRADER:
				return "Trader Options";
			default:
				return "Other Options";
			}

		}
		string getCellNameForTraderSection(int row)
		{
			switch(row)
			{
			case (int) TRADER_ROW.TRADE:
				return  "Trade";

			case (int)TRADER_ROW.NEWS:
				return "News";

			default:
				return "";
			}

		}
		public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
		{
			var cell = new UITableViewCell(UITableViewCellStyle.Default, "");
			var _cellTitle = "";
			switch(indexPath.Section)
			{
			case (int)SECTIONS.TRADER:
				_cellTitle = getCellNameForTraderSection(indexPath.Row);
				break;
			default:
				break;
			}//switch(indexPath.Section)
			cell.TextLabel.Text = _cellTitle;

			return cell;
		}

		public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
		{
			if (indexPath.Section == (int)SECTIONS.TRADER)
			{
				switch(indexPath.Row)
				{
				case (int)TRADER_ROW.TRADE:
					{
						_controller.NavigationController.PushViewController(new  PositionAndTradeController(), true);
						break;
					}
				case (int)TRADER_ROW.NEWS:
					{
						_controller.NavigationController.PushViewController(new NewsFeedController(), true);
						break;
					}
				}//switch(indexPath.Row)
			}//SECTION = TRADER

		}

	}
}

Enums are used for simplicity.  The PositionsAndTradeController and the NewFeedController are controllers similar to RootViewController.  When a certain row is selected, the respective controller is pushed on the navigation controller.

The RootViewContoller looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace iTrade
{
	public partial class RootViewController : UITableViewController
	{
		#region Constructors

		// The IntPtr and initWithCoder constructors are required for controllers that need
		// to be able to be created from a xib rather than from managed code

		public RootViewController (IntPtr handle) : base(handle)
		{
			Initialize ();
		}

		[Export("initWithCoder:")]
		public RootViewController (NSCoder coder) : base(coder)
		{
			Initialize ();
		}

		public RootViewController () : base("RootViewController", null)
		{
			Initialize ();
		}

		void Initialize ()
		{
		}
		public override void ViewDidLoad ()
		{
			Console.WriteLine("RootViewController ViewDidLoad");

			base.ViewDidLoad ();
			this.TableView.Source = new RootDataSource(this);
			this.Title = "iTrade";
			Console.WriteLine("DidLoad End.");
		}

		#endregion

	}
}

An important point to note in the RootViewController, is that the “Source” property of the TableView is used instead of the DataSource

This is a very basic implementation of Navigation controllers.  In the next blog I will show how to implement “login” Controller and present it before the root controller is displayed.

Starting IPhone development with Monotouch

Things I have learnt so far –

Creating  a application using tables.

. Start a project

. Add a navigation controller to your main window

. Update the class name of the view controller (to whatever name you have called it) in Interface builder

. Add a class for view controllers table source (derive from UITableViewSource

. Override various methods

. If you want to load new tables from cells

– Override “RowSelected” Method and use the “PushViewController” method on navigation controller to push a controller object

Hello world!

Welcome to WordPress.com. After you read this, you should delete and write your own post, with a new title above. Or hit Add New on the left (of the admin dashboard) to start a fresh post.

Here are some suggestions for your first post.

  1. You can find new ideas for what to blog about by reading the Daily Post.
  2. Add PressThis to your browser. It creates a new blog post for you about any interesting  page you read on the web.
  3. Make some changes to this page, and then hit preview on the right. You can alway preview any post or edit you before you share it to the world.