Click here to Skip to main content
15,889,034 members
Articles / Programming Languages / C#

MvvmCross - v3 - Writing a First App

Rate me:
Please Sign up or sign in to vote.
4.91/5 (8 votes)
23 Mar 2013Ms-PL2 min read 74.2K   34  
MvvmCross - A CrossPlatform MVVM Sample
<h1>
    MvvmCross TipCalc - Step3 Creating an iOS UI</h1>
<h2>
    Introduction</h2>
<p>
    This article is step&nbsp;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 &#39;Core&#39; Portable Class Library project which contained:</p>
                                <ul>
                                    <li>
                                        our &#39;business logic&#39; - <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&#39;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&#39;ll instead build up a new project &#39;from empty&#39;, 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 &#39;Xamarin.iOS&#39; iPhone application with name <code><font color="#000000">TipCalc.UI.Touch</font></code></p>
                                <p>
                                    Within this, you&#39;ll find the normal iOS application constructs:</p>
                                <ul>
                                    <li>
                                        the Resources folder</li>
                                    <li>
                                        the info.plist &#39;configuration&#39; 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&#39;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&#39;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&#39;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 &#39;standard&#39; 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&lt;IMvxAppStart&gt;();
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(&quot;AppDelegate&quot;)]
    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&lt;IMvxAppStart&gt;();
            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 &#39;iPhone UIViewController&#39; 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&#39;t go into depth here about how to use the XIB iOS editor - instead I&#39;ll just cover the bare basics, and I&#39;ll also try to provide some comparisons for those familiar with XAML.</p>
                                <p>
                                    Drag/drop from the &#39;Object Library&#39; 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 &#39;outlets&#39; 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 &#39;Assistant Editor&#39; from menu option &#39;View&#39; -&gt; &#39;Assistant Editor&#39; -&gt; &#39;Show Assistant Editor&#39; within xCode. This will display a small pane with some ObjectiveC code in it - this is the &#39;Assistant Editor&#39;</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 &#39;pop up&#39; a window listing the &#39;outlets and actions&#39; available for this field</li>
                                    <li>
                                        find the one marked &#39;New Referencing Outlet&#39;</li>
                                    <li>
                                        click on the circle to the right of &#39;New Referencing Outlet&#39; 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) =&gt; vm.Tip ); 
    this.Bind (this.SubTotalTextField, (TipViewModel vm) =&gt; vm.SubTotal );
    this.Bind (this.GenerositySlider, (TipViewModel vm) =&gt; vm.Generosity );
}
</font></code></pre>
                                <p>
                                    What this code does is to generate &#39;in code&#39; exactly the same type of data-binding information as we generated &#39;in XML&#39; 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 (&quot;TipView&quot;, null)
        {
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            this.Bind (this.TipLabel, (TipViewModel vm) =&gt; vm.Tip ); 
            this.Bind (this.SubTotalTextField, (TipViewModel vm) =&gt; vm.SubTotal );
            this.Bind (this.GenerositySlider, (TipViewModel vm) =&gt; 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) =&gt; vm.Tip ); 
</font></code></pre>
                                <p>
                                    what this line means is:</p>
                                <ul>
                                    <li>
                                        bind the <font color="#000000"><code>TipLabel</code>&#39;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>&#39;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 =&gt; label.Text, (TipViewModel vm) =&gt; vm.Tip ); 
</font></code></pre>
                                <p>
                                    In later topics we&#39;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(() =&gt; {
    this.SubTotalTextField.ResignFirstResponder();
}));
</font></code></pre>
                                <h2>
                                    Moving on...</h2>
                                <p>
                                    There&#39;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&#39;s move on to Windows!</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<h2>
    History</h2>
<p>
    22nd March 2013 - First&nbsp;Submission</p>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer Cirrious Ltd
United Kingdom United Kingdom
Developing software since 1982. Currently engrossed in both cloud and mobile technologies. Currently spending far too much time on MvvmCross... and loving every second of it Smile | :)

Comments and Discussions