Click here to Skip to main content
15,892,927 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 - Step2 Creating an Android UI</h1>
<h2>
    Introduction</h2>
<p>
    This article is step&nbsp;2 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">
                <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>
                    So we&#39;re now ready to add out first User Interface.</p>
                <p>
                    So... let&#39;s start with Android.</p>
                <p>
                    To create an Android 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 project.</p>
                <h2>
                    Create a new Android UI Project</h2>
                <p>
                    Add a new project to your solution - a &#39;Xamarin.Android&#39; application with name <code><font color="#000000">TipCalc.UI.Droid</font></code></p>
                <p>
                    Within this, you&#39;ll find the normal Android application constructs:</p>
                <ul>
                    <li>
                        the Assets folder</li>
                    <li>
                        the Resources folder</li>
                    <li>
                        the Activity1.cs</li>
                </ul>
                <h2>
                    Delete Activity1.cs</h2>
                <p>
                    No-one really needs an <font color="#000000"><code>Activity1</code> :)</font></p>
                <p>
                    Also, delete <font color="#000000"><code>Main.axml</code> in the /resources/Layout folder.</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 XML</li>
                        </ul>
                    </li>
                    <li>
                        <strong>Cirrious.MvvmCross.dll</strong>
                        <ul>
                            <li>
                                Mvvm classes - including base classes for your views and viewmodels</li>
                        </ul>
                    </li>
                    <li>
                        <strong>Cirrious.MvvmCross.Plugins.Json.dll</strong>
                        <ul>
                            <li>
                                Adds a PCL Newtonsoft.JSON.Net implementation - our Android UI application will use this to navigate between Activities (pages)</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 - Droid specific versions</h3>
                <p>
                    Add references to the new project for the Xamarin.Android specific libraries:</p>
                <ul>
                    <li>
                        <strong>Cirrious.CrossCore.Droid.dll</strong></li>
                    <li>
                        <strong>Cirrious.MvvmCross.Binding.Droid.dll</strong></li>
                    <li>
                        <strong>Cirrious.MvvmCross.Droid.dll</strong></li>
                </ul>
                <p>
                    Each of these extends the functionality of its PCL counterpart with Android specific additions.</p>
                <p>
                    Normally these will be found in a folder path like <em>{SolutionRoot}/Libs/Mvx/Droid/</em></p>
                <p>
                    Also, within that same folder you need to add:</p>
                <ul>
                    <li>
                        <strong>System.Windows.dll</strong> - <em>Android version</em>
                        <ul>
                            <li>
                                This adds some core PCL adaptation - some &#39;type forwarding&#39; allowing PCL libraries to access things like <font color="#000000"><code>System.Windows.ICommand</code> even though on Xamarin.Android there isn&#39;t really any <code>System.Windows</code> </font></li>
                        </ul>
                    </li>
                </ul>
                <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 the MvvmCross Android binding resource file</h2>
                <p>
                    This file can be found in <a href="https://github.com/slodge/MvvmCross/tree/v3/Cirrious/Cirrious.MvvmCross.Binding.Droid/ResourcesToCopy" rel="nofollow"><u><font color="#0066cc">https://github.com/slodge/MvvmCross/tree/v3/Cirrious/Cirrious.MvvmCross.Binding.Droid/ResourcesToCopy</font></u></a></p>
                <p>
                    It needs to be copied to the <font color="#000000"><code>/Resources/Values</code> folder in your project.</font></p>
                <p>
                    The contents of this file are very simple - but very technical. We&#39;ll return later to talk more about the nodes and attributes declared in this file, and about how they enable declarative data-binding.</p>
                <p>
                    For now, the only line we will use is the core data-binding attribute: <font color="#000000"><code>MvxBind</code> </font></p>
                <pre>
<code><font color="#000000">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
  &lt;declare-styleable name=&quot;MvxBinding&quot;&gt;
    **&lt;attr name=&quot;MvxBind&quot; format=&quot;string&quot;/&gt;**
    &lt;attr name=&quot;MvxLang&quot; format=&quot;string&quot;/&gt;
  &lt;/declare-styleable&gt;
  &lt;declare-styleable name=&quot;MvxListView&quot;&gt;
    &lt;attr name=&quot;MvxItemTemplate&quot; format=&quot;string&quot;/&gt;
    &lt;attr name=&quot;MvxDropDownItemTemplate&quot; format=&quot;string&quot;/&gt;
  &lt;/declare-styleable&gt;
  &lt;item type=&quot;id&quot; name=&quot;MvxBindingTagUnique&quot;/&gt;
  &lt;declare-styleable name=&quot;MvxImageView&quot;&gt;
    &lt;attr name=&quot;MvxSource&quot; format=&quot;string&quot;/&gt;
  &lt;/declare-styleable&gt;
&lt;/resources&gt;
</font></code></pre>
                <h2>
                    Add a Setup class</h2>
                <p>
                    Every MvvmCross UI project requires a <font color="#000000"><code>Setup</code> class.</font></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 Droid 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>
                    <li>
                        some initialisation for the Json.Net plugin and for the navigation mechanism</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 Android.App;
using Android.Content;
using Cirrious.MvvmCross.Droid.Platform;
using Cirrious.MvvmCross.Droid.Views;
using Cirrious.MvvmCross.ViewModels;
using TipCalc.Core;

namespace TipCalc.UI.Droid
{
    public class Setup : MvxAndroidSetup
    {
        public Setup(Context applicationContext) : base(applicationContext)
        {
        }

        protected override IMvxApplication CreateApp()
        {
            return new App();
        }

        protected override IMvxNavigationSerializer CreateNavigationSerializer()
        {
            Cirrious.MvvmCross.Plugins.Json.PluginLoader.Instance.EnsureLoaded(true);
            return new MvxJsonNavigationSerializer();
        }
    }
</font></code></pre>
                <p>
                    <strong>Note:</strong> You may wonder why the Json Navigation is initialized within your <font color="#000000"><code>Setup</code> code, while so much else initialization is done automatically for you. The reason behind this lies in the effort MvvmCross makes to minimize dependencies on external projects. By not including JSON.Net as a reference within MvvmCross itself, this enables developers to later choose a completely different serialization mechanism if they want to - e.g. they are free to choose <code>ServiceStack.Text</code>, <code>System.Xml.Serialization</code> or even some custom binary serializer.</font></p>
                <h2>
                    Add your View</h2>
                <h3>
                    Add the Android Layout XML (AXML)</h3>
                <p>
                    This tutorial doesn&#39;t attempt to give an introduction to Android XML layout.</p>
                <p>
                    Instead all I&#39;ll say here is the bare minimum. If you are new to Android, then you can find out more about Android XML from lots of places including the official documentation at: <a href="http://developer.android.com/guide/topics/ui/declaring-layout.html" rel="nofollow"><u><font color="#0066cc">http://developer.android.com/guide/topics/ui/declaring-layout.html</font></u></a>. If you are coming from a XAML background - you are a <em>XAMLite</em> - then I&#39;ll include some simple XAML-AXML comparisons to help you out.</p>
                <p>
                    To achieve the basic layout:</p>
                <ul>
                    <li>
                        <p>
                            we&#39;ll add a new AXML file - <font color="#000000"><code>View_Tip.axml</code> in the <code>/resources/Layout</code> folder</font></p>
                    </li>
                    <li>
                        <p>
                            we&#39;ll edit this using either the Xamarin Android designer or the Visual Studio XML editor - the designer gives us a visual display, while the VS editor <em>sometimes</em> gives us XML Intellisense.</p>
                        <pre>
<code><font color="#000000">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:orientation=&quot;vertical&quot;
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;fill_parent&quot;&gt;
&lt;/LinearLayout&gt;
</font></code></pre>
                    </li>
                    <li>
                        <p>
                            we&#39;ll add a local app namespace - <strong><a href="http://schemas.android.com/apk/res/TipCalc.UI.Droid" rel="nofollow"><u><font color="#0066cc">http://schemas.android.com/apk/res/TipCalc.UI.Droid</font></u></a></strong> - this is just like adding a namespace in XAML.</p>
                        <pre>
<code><font color="#000000">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:local=&quot;http://schemas.android.com/apk/res/TipCalc.UI.Droid&quot;
    android:orientation=&quot;vertical&quot;
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;fill_parent&quot;&gt;
&lt;/LinearLayout&gt;
</font></code></pre>
                    </li>
                    <li>
                        <p>
                            notice that this &#39;layout&#39; is already by default a <strong>vertical</strong> <font color="#000000"><code>LinearLayout</code> - for XAMLites, this layout is just like a <code>StackPanel</code> except that it is <strong>very important</strong> to specify the <strong>vertical</strong> orientation</font></p>
                    </li>
                    <li>
                        <p>
                            within this layout we&#39;ll add some <font color="#000000"><code>TextView</code>s to provide some static text labels - for XAMLites, these are like <code>TextBlock</code>s</font></p>
                        <pre>
<code><font color="#000000">&lt;TextView
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;SubTotal&quot; /&gt;
&lt;TextView
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;Generosity&quot; /&gt;
&lt;TextView
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;Tip to leave&quot; /&gt;
</font></code></pre>
                    </li>
                    <li>
                        <p>
                            we&#39;ll also add a short, wide <font color="#000000"><code>View</code> with a yellow background to provide a small amount of chrome:</font></p>
                        <pre>
<code><font color="#000000">&lt;View
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;1dp&quot;
    android:background=&quot;#ffff00&quot; /&gt;
</font></code></pre>
                    </li>
                    <li>
                        <p>
                            we&#39;ll add some <font color="#000000"><code>View</code>s for data display and entry, and we&#39;ll <strong>databind</strong> these <code>View</code>s to properties in our <code>TipViewModel</code> </font></p>
                        <ul>
                            <li>
                                <p>
                                    an <font color="#000000"><code>EditText</code> for text data entry of the <code>SubTotal</code> - for XAMLites, this is a <code>TextBox</code></font></p>
                                <pre>
<code><font color="#000000">&lt;EditText
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    local:MvxBind=&quot;Text SubTotal&quot; /&gt;
</font></code></pre>
                            </li>
                            <li>
                                <p>
                                    a <font color="#000000"><code>SeekBar</code> for touch/slide entry of the <code>Generosity</code> - for XAMLites, this is like a <code>ProgressBar</code></font></p>
                                <pre>
<code><font color="#000000">&lt;SeekBar
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:max=&quot;40&quot;
    local:MvxBind=&quot;Progress Generosity&quot; /&gt;
</font></code></pre>
                            </li>
                            <li>
                                <p>
                                    we&#39;ll add a <font color="#000000"><code>TextView</code> to display the <code>Tip</code> that results from the calculation:</font></p>
                                <pre>
<code><font color="#000000">&lt;TextView
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    local:MvxBind=&quot;Text Tip&quot; /&gt;
</font></code></pre>
                            </li>
                        </ul>
                    </li>
                </ul>
                <p>
                    Put together, this looks like:</p>
                <pre>
<code><font color="#000000">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:local=&quot;http://schemas.android.com/apk/res/TipCalc.UI.Droid&quot;
    android:orientation=&quot;vertical&quot;
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;fill_parent&quot;&gt;
    &lt;TextView
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;SubTotal&quot; /&gt;
    &lt;EditText
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        local:MvxBind=&quot;Text SubTotal&quot; /&gt;
    &lt;TextView
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Generosity&quot; /&gt;
    &lt;SeekBar
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:max=&quot;40&quot;
        local:MvxBind=&quot;Progress Generosity&quot; /&gt;
    &lt;View
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;1dp&quot;
        android:background=&quot;#ffff00&quot; /&gt;
    &lt;TextView
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Tip to leave&quot; /&gt;
    &lt;TextView
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        local:MvxBind=&quot;Text Tip&quot; /&gt;
&lt;/LinearLayout&gt;
</font></code></pre>
                <h3>
                    About the data-binding syntax</h3>
                <p>
                    Each of the data-binding blocks within our first sample looks similar:</p>
                <pre>
<code><font color="#000000">local:MvxBind=&quot;Text SubTotal&quot;
</font></code></pre>
                <p>
                    What this line means is:</p>
                <ul>
                    <li>
                        data-bind:
                        <ul>
                            <li>
                                the property <font color="#000000"><code>Text</code> on the <code>View</code> </font></li>
                            <li>
                                to the property <font color="#000000"><code>SubTotal</code> on the <code>DataContext</code> - which in this case will be a <code>TipViewModel</code> </font></li>
                        </ul>
                    </li>
                    <li>
                        so:
                        <ul>
                            <li>
                                whenever the <font color="#000000"><code>TipViewModel</code> calls <code>RaisePropertyChanged</code> on <code>SubTotal</code> then the <code>View</code> should update</font></li>
                            <li>
                                and whenever the user enters text into the <font color="#000000"><code>View</code> then the <code>SubTotal</code> value should be <code>set</code> on the <code>TipViewModel</code> </font></li>
                        </ul>
                    </li>
                </ul>
                <p>
                    Note that this <font color="#000000"><code>TwoWay</code> binding is <strong>different</strong> to XAML where generally the default <code>BindingMode</code> is only <code>OneWay</code>.</font></p>
                <p>
                    In later topics, we&#39;ll return to show you more options for data-binding, including how to use <font color="#000000"><code>ValueConverter</code>s, but for now all our binding uses this simple <code>ViewProperty ViewModelProperty</code> syntax.</font></p>
                <h3>
                    Add the View class</h3>
                <p>
                    With our AXML layout complete, we can now add the C# <font color="#000000"><code>Activity</code> which is used to display this content. For developers coming from XAML backgrounds, these <code>Activity</code> classes are roughly equivalent to <code>Page</code> objects in WindowsPhone on WindowsStore applications - they own the &#39;whole screen&#39; and have a lifecycle which means that only one of them is shown at any one time.</font></p>
                <p>
                    To create our <font color="#000000"><code>Activity</code> - which will also be our Mvvm <code>View</code>:</font></p>
                <ul>
                    <li>
                        <p>
                            Create a Views folder within your TipCalc.UI.Droid project</p>
                    </li>
                    <li>
                        <p>
                            Within this folder create a new C# class - <code><font color="#000000">TipView</font></code></p>
                    </li>
                    <li>
                        <p>
                            This class will:</p>
                        <ul>
                            <li>
                                <p>
                                    inherit from <code><font color="#000000">MvxActivity</font></code></p>
                                <pre>
<code><font color="#000000">public class TipCalcView : MvxActivity
</font></code></pre>
                            </li>
                            <li>
                                <p>
                                    be marked with the Xamarin.Android <font color="#000000"><code>Activity</code> attribute, marking it as the <code>MainLauncher</code> for the project</font></p>
                                <pre>
<code><font color="#000000">[Activity(MainLauncher=true)]
</font></code></pre>
                            </li>
                            <li>
                                <p>
                                    provide a <font color="#000000"><code>new ViewModel</code> Property to specify the type of ViewModel it expects - the <code>TipViewModel</code></font></p>
                                <pre>
<code><font color="#000000">public new TipViewModel ViewModel
{
    get { return (TipViewModel)base.ViewModel; }
    set { base.ViewModel = value; }
}
</font></code></pre>
                            </li>
                            <li>
                                <p>
                                    use <font color="#000000"><code>OnViewModelSet</code> to inflate its <code>ContentView</code> from the AXML - this will use a resource identifier generated by the Android and Xamarin tools. </font></p>
                                <pre>
<code><font color="#000000">protected override void OnViewModelSet()
{
    SetContentView(Resource.Layout.View_Tip);
}
</font></code></pre>
                            </li>
                        </ul>
                    </li>
                </ul>
                <p>
                    As a result this completed class is very simple:</p>
                <pre>
<code><font color="#000000">using Android.App;
using Cirrious.MvvmCross.Droid.Views;
using TipCalc.Core;

namespace TipCalc.UI.Droid.Views
{
    [Activity(Label = &quot;Tip&quot;, MainLauncher = true)]
    public class TipView : MvxActivity
    {
        public new TipViewModel ViewModel
        {
            get { return (TipViewModel) base.ViewModel; }
            set { base.ViewModel = value; }
        }

        protected override void OnViewModelSet()
        {
            base.OnViewModelSet();
            SetContentView(Resource.Layout.View_Tip);
        }
    }
}
</font></code></pre>
                <h2>
                    The Android 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_Android.png"></p>
                <p>
                    If you then want to make it &#39;more beautiful&#39;, then try adding a few attributes to some of your AXML - things like:</p>
                <pre>
<code><font color="#000000">    android:background=&quot;#00007f&quot;
    android:textColor=&quot;#ffffff&quot;
    android:textSize=&quot;24dp&quot;
    android:layout_margin=&quot;30dp&quot;
    android:padding=&quot;20dp&quot;
    android:layout_marginTop=&quot;10dp&quot;
</font></code></pre>
                <p>
                    Within a very short time, you should hopefully be able to create something &#39;styled&#39;...</p>
                <p>
                    <img alt="v2" src="https://raw.github.com/slodge/MvvmCross/v3/v3Tutorial/Pictures/TipCalc_Android_Styled.png"></p>
                <p>
                    ... but actually making it look &#39;nice&#39; might take some design skills!</p>
                <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 Xamarin.iOS and to Windows!</p>
            </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