<h1>
MvvmCross TipCalc - Step3 Creating an iOS UI</h1>
<h2>
Introduction</h2>
<p>
This article is step 3 in the TipCalc tutorial for MvvmCross v3 - Hot Tuna!</p>
<h2>
The story so far...</h2>
<div id="wiki-content">
<div class="wrap">
<div class="gollum-markdown-content instapaper_body" id="wiki-body">
<div class="markdown-body">
<div id="wiki-content">
<div class="wrap">
<div class="gollum-markdown-content instapaper_body" id="wiki-body">
<div class="markdown-body">
<p>
We started with the goal of creating an app to help calculate what tip to leave in a restaurant</p>
<p>
We had a plan to produce a UI based on this concept:</p>
<p>
<img alt="Sketch" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Sketch.png"></p>
<p>
To satisfy this we built a 'Core' Portable Class Library project which contained:</p>
<ul>
<li>
our 'business logic' - <font color="#000000"><code>ICalculation</code> </font></li>
<li>
our ViewModel - <font color="#000000"><code>TipViewModel</code> </font></li>
<li>
our <font color="#000000"><code>App</code> which contains the application wiring, including the start instructions.</font></li>
</ul>
<p>
We then added our first User Interface - for Xamarin.Android:</p>
<p>
<img alt="Android" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Android_Styled.png"></p>
<p>
For our next project, let's shift to Xamarin.iOS.</p>
<p>
To create an iPhone MvvmCross UI, you can use the Visual Studio project template wizards, but here we'll instead build up a new project 'from empty', just as we did for the Core and Android projects.</p>
<p>
Also, to work with iPhone, for now we will switch to working on the Mac with Xamarin Studio</p>
<h2>
Create a new iOS UI Project</h2>
<p>
Add a new project to your solution - a 'Xamarin.iOS' iPhone application with name <code><font color="#000000">TipCalc.UI.Touch</font></code></p>
<p>
Within this, you'll find the normal iOS application constructs:</p>
<ul>
<li>
the Resources folder</li>
<li>
the info.plist 'configuration' information</li>
<li>
the AppDelegate.cs class</li>
<li>
the Main.cs class</li>
<li>
the MyViewController.cs class</li>
</ul>
<h2>
Delete MyViewController.cs</h2>
<p>
No-one really needs an <font color="#000000"><code>MyViewController</code> :)</font></p>
<p>
Also, delete <font color="#000000"><code>MyViewController.xib</code> (if there is one)</font></p>
<h2>
Add references</h2>
<h3>
Add references to CoreCross, Binding and MvvmCross - PCL versions</h3>
<p>
Add references to the new project for the portable libraries:</p>
<ul>
<li>
<strong>Cirrious.CrossCore.dll</strong>
<ul>
<li>
core interfaces and concepts including Trace, IoC and Plugin management</li>
</ul>
</li>
<li>
<strong>Cirrious.MvvmCross.Binding.dll</strong>
<ul>
<li>
DataBinding classes - which you'll mainly use from C# code</li>
</ul>
</li>
<li>
<strong>Cirrious.MvvmCross.dll</strong>
<ul>
<li>
Mvvm classes - including base classes for your views and viewmodels</li>
</ul>
</li>
</ul>
<p>
Normally these will be found in a folder path like <em>{SolutionRoot}/Libs/Mvx/Portable/</em></p>
<h3>
Add references to CoreCross, Binding and MvvmCross - iOS specific versions</h3>
<p>
Add references to the new project for the Xamarin.iOS specific libraries:</p>
<ul>
<li>
<strong>Cirrious.CrossCore.Touch.dll</strong></li>
<li>
<strong>Cirrious.MvvmCross.Binding.Touch.dll</strong></li>
<li>
<strong>Cirrious.MvvmCross.Touch.dll</strong></li>
</ul>
<p>
Each of these extends the functionality of its PCL counterpart with iOS specific additions.</p>
<p>
Normally these will be found in a folder path like <em>{SolutionRoot}/Libs/Mvx/Touch/</em></p>
<p>
Also, within that same folder you need to add:</p>
<h3>
Add a reference to TipCalc.Core.csproj</h3>
<p>
Add a reference to your <font color="#000000"><code>TipCalc.Core</code> project - the project we created in the last step which included:</font></p>
<ul>
<li>
your <font color="#000000"><code>Calculation</code> service, </font></li>
<li>
your <font color="#000000"><code>TipViewModel</code> </font></li>
<li>
your <font color="#000000"><code>App</code> wiring.</font></li>
</ul>
<h2>
Add a Setup class</h2>
<p>
Just as we said during the Android construction <em>Every MvvmCross UI project requires a <font color="#000000"><code>Setup</code> class</font></em></p>
<p>
This class sits in the root namespace (folder) of our UI project and performs the initialisation of the MvvmCross framework and your application, including:</p>
<ul>
<li>
the Inversion of Control (IoC) system</li>
<li>
the MvvmCross data-binding</li>
<li>
your <font color="#000000"><code>App</code> and its collection of <code>ViewModel</code>s</font></li>
<li>
your UI project and its collection of <font color="#000000"><code>View</code>s</font></li>
</ul>
<p>
Most of this functionality is provided for you automatically. Within your iOS UI project all you have to supply are:</p>
<ul>
<li>
your <font color="#000000"><code>App</code> - your link to the business logic and <code>ViewModel</code> content</font></li>
</ul>
<p>
For <font color="#000000"><code>TipCalc</code> here's all that is needed in Setup.cs:</font></p>
<pre>
<code><font color="#000000">using System;
using Cirrious.MvvmCross.Touch.Platform;
using TipCalc.Core;
using Cirrious.MvvmCross.Touch.Views.Presenters;
namespace TipCalc.UI.Touch
{
public class Setup : MvxTouchSetup
{
public Setup (MvxApplicationDelegate appDelegate, IMvxTouchViewPresenter presenter)
: base(appDelegate, presenter)
{
}
protected override Cirrious.MvvmCross.ViewModels.IMvxApplication CreateApp ()
{
return new App();
}
}
}
</font></code></pre>
<h2>
Modify the AppDelegate to use Setup</h2>
<p>
Your <font color="#000000"><code>AppDelegate</code> provides a set of callback that iOS uses to inform you about events in your application's lifecycle.</font></p>
<p>
To use this <font color="#000000"><code>AppDelegate</code> within MvvmCross, we need to:</font></p>
<ul>
<li>
<p>
modify it so that it inherits from <font color="#000000"><code>MvxApplicationDelegate</code> instead of <code>UIApplicationDelegate</code></font></p>
<pre>
<code><font color="#000000">public partial class AppDelegate : MvxApplicationDelegate
</font></code></pre>
</li>
<li>
<p>
modify it so that the method that is called on startup (FinishedLaunching) does some UI application setup:</p>
<ul>
<li>
<p>
create a new presenter - this is the class that will determine how Views are shown - for this sample, we choose a 'standard' one:</p>
<pre>
<code><font color="#000000">var presenter = new MvxTouchViewPresenter(this, window);
</font></code></pre>
</li>
<li>
<p>
create and call Initialize on a <font color="#000000"><code>Setup</code>:</font></p>
<pre>
<code><font color="#000000">var setup = new Setup(this, presenter);
setup.Initialize();
</font></code></pre>
</li>
<li>
<p>
with <font color="#000000"><code>Setup</code> completed, use the <code>Mvx</code> Inversion of Control container in order to find and <code>Start</code> the <code>IMvxAppStart</code> object:</font></p>
<pre>
<code><font color="#000000">var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
</font></code></pre>
</li>
</ul>
</li>
</ul>
<p>
Together, this looks like:</p>
<pre>
<code><font color="#000000">using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Cirrious.MvvmCross.Touch.Platform;
using Cirrious.MvvmCross.Touch.Views.Presenters;
using Cirrious.MvvmCross.ViewModels;
using Cirrious.CrossCore.IoC;
namespace TipCalc.UI.Touch
{
[Register("AppDelegate")]
public partial class AppDelegate : MvxApplicationDelegate
{
UIWindow window;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
var presenter = new MvxTouchViewPresenter(this, window);
var setup = new Setup(this, presenter);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
window.MakeKeyAndVisible();
return true;
}
}
}
</font></code></pre>
<h2>
Add your View</h2>
<h3>
Create an initial UIViewController</h3>
<p>
Create a Views folder</p>
<p>
Within this, add a new 'iPhone UIViewController' and call it <code><font color="#000000">TipView</font></code></p>
<p>
This will generate:</p>
<ul>
<li>
TipView.cs</li>
<li>
TipView.designer.cs</li>
<li>
TipView.xib</li>
</ul>
<h3>
Edit the XIB layout</h3>
<p>
Double click on the XIB file</p>
<p>
This will open the XIB editor within xCode.</p>
<p>
Just as we did with Android, I won't go into depth here about how to use the XIB iOS editor - instead I'll just cover the bare basics, and I'll also try to provide some comparisons for those familiar with XAML.</p>
<p>
Drag/drop from the 'Object Library' to add:</p>
<ul>
<li>
some <font color="#000000"><code>UILabel</code>s for showing static text - these are like <code>TextBlock</code>s</font></li>
<li>
a <font color="#000000"><code>UITextField</code> for editing the <code>SubTotal</code> - this is like a <code>TextBox</code> </font></li>
<li>
a <font color="#000000"><code>UISlider</code> for editing the <code>Generosity</code> - this is like a <code>ProgressBar</code> </font></li>
<li>
a <font color="#000000"><code>UILabel</code> for showing the <code>Tip</code> result - this is like a <code>TextBlock</code> </font></li>
</ul>
<p>
Using drag and drop, you should be able to quite quickly generate a design similar to:</p>
<p>
<img alt="design" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Touch_Design.png"></p>
<h3>
Create 'outlets' within the XIB editor</h3>
<p>
Once you have your UI drawn, you can then link those UI displayed fields to ObjectiveC variables called <font color="#000000"><code>outlet</code>s.</font></p>
<p>
After you have done this, then the Xamarin.iOS tools within Xamarin Studio will then automaticallly detect these changes and map those ObjectiveC fields to C# properties back in your iOS app.</p>
<p>
To start doing this, you need to open the 'Assistant Editor' from menu option 'View' -> 'Assistant Editor' -> 'Show Assistant Editor' within xCode. This will display a small pane with some ObjectiveC code in it - this is the 'Assistant Editor'</p>
<p>
Once you have done this, then you can ctrl-click (right click) on each of the 3 <font color="#000000"><code>SubTotal</code>, <code>Generosity</code> and <code>Tip</code> fields in turn. </font></p>
<p>
<img alt="outlet" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Touch_Outlet.png"></p>
<p>
For each of them:</p>
<ul>
<li>
ctrl-click the UI field in the designer</li>
<li>
this will 'pop up' a window listing the 'outlets and actions' available for this field</li>
<li>
find the one marked 'New Referencing Outlet'</li>
<li>
click on the circle to the right of 'New Referencing Outlet' and drag that to the Assistant Editor.</li>
<li>
drop the field on the Assistant Editor</li>
<li>
it will then ask you to provide a name for your <font color="#000000"><code>outlet</code> option</font></li>
</ul>
<p>
Following this process you should be able to create three ObjectiveC <font color="#000000"><code>outlet</code> variables for the three fields:</font></p>
<ul>
<li>
<code><font color="#000000">SubTotalTextField</font></code></li>
<li>
<code><font color="#000000">GenerositySlider</font></code></li>
<li>
<code><font color="#000000">TipLabel</font></code></li>
</ul>
<p>
With this done, save your xCode changes (using the File Menu) and then exit xCode.</p>
<h3>
Edit TipView.cs</h3>
<p>
Back in Xamarin Studio, you should now see that the Xamarin products have updated the TipView.designer.cs file - it will now contain three <font color="#000000"><code>[Outlet]</code> properties with those same three names</font></p>
<ul>
<li>
<code><font color="#000000">SubTotalTextField</font></code></li>
<li>
<code><font color="#000000">GenerositySlider</font></code></li>
<li>
<code><font color="#000000">TipLabel</font></code></li>
</ul>
<p>
Close the TipView.designer.cs file - this file is an auto-generated <font color="#000000"><code>partial</code> class, and Xamarin Studio can regenerate it at any time - so there is no point in editing it yourself.</font></p>
<p>
Instead open TipView.cs - this contains an editable part of the same <font color="#000000"><code>partial</code> class</font></p>
<p>
Because we want our <font color="#000000"><code>TipView</code> to be not only a <code>UIViewController</code> but also an Mvvm <code>View</code>, then change the inheritance of <code>TipView</code> so that it inherits from <code>MvxViewController</code></font></p>
<pre>
<code><font color="#000000">public class TipView : MvxViewController
</font></code></pre>
<p>
Now, to link <font color="#000000"><code>TipView</code> to <code>TipViewModel</code> create a <code>public new TipViewModel ViewModel</code> property - exactly as you did in Xamarin.Android:</font></p>
<pre>
<code><font color="#000000">public new TipViewModel ViewModel
{
get { return (TipViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
</font></code></pre>
<p>
To add the data-binding code, go to the <font color="#000000"><code>ViewDidLoad</code> method in your <code>TipView</code> class. This is a method that will be called after the View is loaded within iOS but before it is displayed on the screen.</font></p>
<p>
This makes <font color="#000000"><code>ViewDidLoad</code> a perfect place for us to call some data-binding extension methods which will specify how we want the UI data-bound to the ViewModel:</font></p>
<pre>
<code><font color="#000000">public override void ViewDidLoad ()
{
base.ViewDidLoad ();
this.Bind (this.TipLabel, (TipViewModel vm) => vm.Tip );
this.Bind (this.SubTotalTextField, (TipViewModel vm) => vm.SubTotal );
this.Bind (this.GenerositySlider, (TipViewModel vm) => vm.Generosity );
}
</font></code></pre>
<p>
What this code does is to generate 'in code' exactly the same type of data-binding information as we generated 'in XML' in Android.</p>
<p>
<strong>Note</strong> that before the calls to <font color="#000000"><code>this.Bind</code> are made, then we first call <code>base.ViewDidLoad()</code>. This is important because <code>base.ViewDidLoad()</code> is where MvvmCross locates the <code>TipViewModel</code> that this <code>TipView</code> will bind to.</font></p>
<p>
Altogether this looks like:</p>
<pre>
<code><font color="#000000">using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.MvvmCross.Binding.BindingContext;
using TipCalc.Core;
namespace TipCalc.UI.Touch
{
public partial class TipView : MvxViewController
{
public new TipViewModel ViewModel
{
get { return (TipViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
public TipView () : base ("TipView", null)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
this.Bind (this.TipLabel, (TipViewModel vm) => vm.Tip );
this.Bind (this.SubTotalTextField, (TipViewModel vm) => vm.SubTotal );
this.Bind (this.GenerositySlider, (TipViewModel vm) => vm.Generosity );
}
}
}
</font></code></pre>
<h3>
Binding in Xamarin.iOS</h3>
<p>
You will no doubt have noticed that data-binding in iOS looks very different to the way it looked in Android - and to what you may have expected from XAML.</p>
<p>
This is because the XIB format used in iOS is a lot less human manipulable and extensible than the XML formats used in Android AXML and Windows XAML - so it makes more sense to use C# rather than the XIB to register our bindings.</p>
<p>
Within this section of the tutorial all of our iOS bindings look like:</p>
<pre>
<code><font color="#000000"> this.Bind (this.TipLabel, (TipViewModel vm) => vm.Tip );
</font></code></pre>
<p>
what this line means is:</p>
<ul>
<li>
bind the <font color="#000000"><code>TipLabel</code>'s default binding property - which happens to be a property called <code>Text</code> </font></li>
<li>
to the <font color="#000000"><code>ViewModel</code>'s Tip property</font></li>
</ul>
<p>
As with Android, this will be a <font color="#000000"><code>TwoWay</code> binding by default - which is different to what XAML developers may expect to see.</font></p>
<p>
If you had wanted to specify the <font color="#000000"><code>TipLabel</code> property to use instead of relying on the default, then you could have done this with:</font></p>
<pre>
<code><font color="#000000"> this.Bind (this.TipLabel, label => label.Text, (TipViewModel vm) => vm.Tip );
</font></code></pre>
<p>
In later topics we'll cover more on binding in iOS, including more on binding to non-default fields; other code-based binding code mechanisms; custom bindings; using <font color="#000000"><code>ValueConverter</code>s; and creating bound sub-views.</font></p>
<h2>
The iOS UI is complete!</h2>
<p>
At this point you should be able to run your application.</p>
<p>
When it starts... you should see:</p>
<p>
<img alt="v1" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Touch_Sim.png"></p>
<p>
This seems to work perfectly, although you may notice that if you tap on the <font color="#000000"><code>SubTotal</code> property and start entering text, then you cannot afterwards close the keyboard.</font></p>
<p>
This is a View concern - it is a UI problem. So we can fix it just in the iOS UI code - in this View. For example, to fix this here, you can add a gesture recognizer to the end of the <font color="#000000"><code>ViewDidLoad</code> method like:</font></p>
<pre>
<code><font color="#000000">View.AddGestureRecognizer(new UITapGestureRecognizer(() => {
this.SubTotalTextField.ResignFirstResponder();
}));
</font></code></pre>
<h2>
Moving on...</h2>
<p>
There's more we could do to make this User Interface nicer and to make the app richer... but for this first application, we will leave it here for now.</p>
<p>
Let's move on to Windows!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<h2>
History</h2>
<p>
22nd March 2013 - First Submission</p>