Cross-Platform Mobile Dev, pure badassery – pt 3

By | October 16, 2012

This is part 3 of a 5-part series in which I explore and demonstrate cross-platform app creation for mobile and desktop platforms using iFactr, an enterprise-grade framework, and Monocross, the open-source core of iFactr. The other articles are easily accessible at the bottom of each post.

Now that you’ve seen how things are done in iFactr, which abstracts not only the business logic of your application, but also the UI and even the data access layer, let’s have a look at how we might do things in Monocross – the open-source project on which iFactr is built. Monocross provides a common business logic and navigation layer, free of charge! The only thing left for you to do is implement the View on the platform(s) of your choice. Monocross is also a great alternative if you find that you are having to customize a lot of iFactr’s UI w/ platform-specific code; you may just want to do the UI for each platform in its entirety.

Let me preface the subsequent blog posts w/ the following: I have never used MonoCross until this very moment. So, keep that in mind as you and I both walk through figuring this out and making something kick ass :)

First, go grab the Monocross templates for Visual Studio (that’s right, I’m going to ignore iOs this time around because hey, it’s my freakin’ blog).

Create your first Monocross application in VS:

image

I’m going to start this one the same way we did the last; by creating “Hello World” for multiple platforms, then augmenting that in to the MonkeySpace example. Since I have virtually no experience with Android or Webkit, I’ll be sticking with Windows WPF, Windows Phone and Console for the deployment targets.

So let’s start with a Console container for now, since it’ll be easy for me to crank out something that proves this stuff works ;)

image

Now our project looks something like this:

image

Let’s dissect the code and figure out what’s happening.

App.cs:

	public class App : MXApplication
	{
		public override void OnAppLoad ()
		{
			Title = "Hello World!";

			// add controllers to navigation map
			NavigationMap.Add ("", new Controllers.MessageController ());

			// set navigate on load endpoint
			NavigateOnLoad = "";
		}
	}

well now that looks quite familiar, doesn’t it? Obviously we’re creating that navigation map in much the same manner as you’d see in ASP.Net MVC. However there’s an important distinction with Monocross, the NavigationMap’s values are Controllers, not Layers (UI). Keep this in mind as we move on.
Another note is that App inherits from MXApplication now, not an iFactr IApp.

Let’s have a look at the Controller we’re referencing here:

	public class MessageController : MXController
	{
		public override string Load (Dictionary parameters)
		{
			Model = "Hello World";
			return ViewPerspective.Default;
		}
	}

So the important thing here is that the Controller inherits from MXController, which has a generic specifying the Model type that the Controller/View are going to use. Here, the denotes that Model will be a string. If it was “Customer”, then Model would be of type Customer. In this way, we can populate the model accordingly – we’ll see later how this figures in to the UI layers. For now, let’s ignore ViewPerspective, it’s more of an advanced topic for later stuff (from what I’ve seen).

Now let’s move up in to the Container (UI) for the Console and have a look at MessageView.cs:

	public class MessageView : MXView
	{
		public override void Render ()
		{
			System.Console.WriteLine (Model);
		}
	}

Notice here what MXView is using as its Generic type, ‘string’ as well. Also notice the ‘Render’ method is an override, this is the method, much like Load in iFactr, that is called when the Controller signals navigation to a view in the container. Let’s tie it all together with Program.cs:

	public class Program
	{
		static void Main (string[] args)
		{
			// initialize container
			// example: MXConsoleContainer.Initialize(new MyApp.App());

			// initialize views
			MXConsoleContainer.AddView (new Views.MessageView (), ViewPerspective.Default);

			// navigate to first view
			MXConsoleContainer.Navigate (MXContainer.Instance.App.NavigateOnLoad);
		}
	}

You can see here the commented out code looks a lot like what we saw in iFactr. Much like iFactr, this Container project will need a reference to the Application project, and then we can comment out that “example:” line and wire it up accordingly.
Further examination: Notice the AddView; this adds a view to the Console Container for views with a model of type “string”, and associates it with the MessageView() that we saw above.

So let’s wire up the Container to the App, and give ‘er a go:

image

and in Program.cs:

			// initialize container
			MXConsoleContainer.Initialize (new MonkeySpaceMX.App ());

and let ‘er rip!

image

I had to execute the .exe from the cmd line manually because it was simply printing out “Hello World” and then closing the window. But there you have it!

Now let’s add on another container to this same solution so we can see exactly how MX makes itself useful. Before I do this, though, I’m going to admit that I lied. Since a Webkit container comes w/ the MX templates, I’m going to make use of that as a way to quickly fab up another one for this demo.

image image

And, much like Console, let’s wire this up to the App. In the Global.asax.cs:

		protected void Session_Start ()
		{
			// initialize app
			// MXWebkitContainer.Initialize(new MyApp.App());

			// add views to container
			MXWebkitContainer.AddView (new Views.MessageView (), ViewPerspective.Default);
		}

becomes

		protected void Session_Start ()
		{
			// initialize app
			MXWebkitContainer.Initialize (new MonkeySpaceMX.App ());

			// add views to container
			MXWebkitContainer.AddView (new Views.MessageView (), ViewPerspective.Default);
		}

and we also add the reference:

image

And with just doing that, notice no change to our business logic layer:

image

That’s all for this installment. Next time I’ll be taking this project and converting it in to the MonkeySpace one previously done in iFactr.