Writing Cross-Platform Mobile Apps with Visual Studio 2015 and Xamarin Forms

I love writing apps for Windows and Windows Phone. But the rest of the world doesn’t share that love with me. You can write the coolest mobile app in the world, but unless it runs on iOS and Android, few people will care.

Since 2011, Xamarin has offered a compelling solution to developers who write mobile apps but lack the time or wherewithal to port them to all the popular mobile operating systems. With a heritage rooted in Mono, MonoTouch, and Mono for Android, Xamarin allows developers to write mobile apps in C# and compile them into native apps for iOS, Android, Windows Phone, and other popular platforms. Xamarin apps utilize APIs that derive from Microsoft .NET APIs, but also enjoy the ability to invoke native platform APIs when the need arises. A typical Xamarin app consists of per-platform UIs backed by a shared code base written in C# and compiled into a Portable Class Library (PCL). Developers who are familiar with Microsoft .NET find themselves immediately at home in Xamarin because they’re largely insulated from the underlying operating system’s native APIs. Much of the learning curve comes in learning how to build UIs using idioms specific to each platform.

In 2014, Xamarin introduced Xamarin.Forms (hereafter referred to as “Xamarin Forms”), which allow UIs to be shared across platforms, too. Developers who have written for WPF, Silverlight, Windows, or Windows Phone have a leg up on the competition because Xamarin Forms rely on XAML. In Xamarin Forms, you can use XAML to define a UI, and that UI will work on iOS, Android, and Windows Phone. That XAML can be declarative – angle brackets and element declarations – or it can be imperative, with elements instantiated programmatically and wired together to form visual trees. Under the hood, the XAML elements you instantiate or declare render native UI widgets. It may be an <Entry> element in XAML, but it’s a native UITextView in iOS, an EditText control in Android, and a TextBox control in Windows Phone.

This is the first in a series of posts I have planned to introduce developers – especially developers versed in Microsoft XAML – to Xamarin Forms. The sample code presented here uses Xamarin Forms 1.3 and was built using preview versions of Microsoft’s Visual Studio 2015. In order to build it and run it yourself, you’ll need to download and install Xamarin for Visual Studio. And in order to build for iOS and test in an iOS simulator, you’ll need a Mac or MacBook with the Xamarin.iOS tools installed. You’ll also need to configure it to act as a build server for Visual Studio. For more information on compiling and running iOS apps from Visual Studio, refer to this article on the Xamarin Web site.

Xamarin Forms RPN Calculator

When I set out to learn a new platform, I often begin by writing a Reverse Polish Notation (RPN) calculator – which, coincidentally, is the only kind of calculator I can use. (IMHO, a calculator with an equals button isn’t really a calculator; it’s a poor imitation of one. But I digress.) Here’s my Xamarin Forms RPN calculator on Windows Phone, Android, and iOS, in that order:

Calculator-Group

Note that there isn’t a single line of platform-specific code or XAML in this app. (I did use Xamarin Forms’ awesome OnPlatform feature to tweak the UI for individual platforms, but more about that in a moment.) One XAML file – CalculatorPage.xaml, plus the code-behind file CalculatorPage.xaml.cs – serves all three platforms. The app uses the popular Model-View-ViewModel (MVVM) pattern, so CalculatorPage.xaml contains little more than the XAML definition of the app’s one and only view. The logic that drives the view resides in a view-model class named CalculatorViewModel, which in turn relies on a series of helper classes, one of which models an RPN calculator and is named Calculator. The Calculator class, the CalculatorViewModel class, and all the other classes that serve the app are written in C# and compiled into a PCL that serves the iOS, Android, and Windows Phone versions of the app. If you’d like to peruse the source code for yourself, or build the app and see it run, you can download a zip file containing the solution and open it in Visual Studio.

Xamarin Forms Quick Start

In case this is your first experience with Xamarin Forms, here’s my 3-minute synopsis of what you need to know to get started.

Once Xamarin for Visual Studio is installed, you can create a new Xamarin Forms solution using Visual Studio’s File-New-Project command. Select “Mobile Apps” on the left and “Blank App (Xamarin.Forms.Portable)” on the right, as pictured below.

image

The resulting solution contains four projects. One builds into a Portable Class Library containing shared code and resources. The others produce native packages for iOS, Android, and Windows Phone:

image

The Portable project contains a file named App.cs that implements a class named App, which is derived from Xamarin.Forms.Application. Visual Studio provides the following default constructor:

public App()
{
    // The root page of your application
    MainPage = new ContentPage
    {
        Content = new StackLayout
        {
            VerticalOptions = LayoutOptions.Center,
            Children = {
                new Label {
                    XAlign = TextAlignment.Center,
                    Text = "Welcome to Xamarin Forms!"
                }
            }
        }
    };
}

This constructor programmatically creates a XAML UI consisting of a ContentPage containing a StackLayout (think StackPanel if you’re familiar with Microsoft XAML), which in turn contains a Label (similar to TextBlock). Assigning the ContentPage to App’s MainPage property makes this the page that’s displayed when the app starts up. If you run the app right now, here’s how it will look on Windows Phone:

lumia920blue_portrait

You could proceed down the path that Visual Studio started and build out an entire UI programmatically. But if you prefer to build UIs declaratively, you need to make a few changes. First, use Visual Studio’s Add New Item command to add a new XAML file to the Portable project. Select “Forms Xaml Page” as the item type, and change Page1.cs to MainPage.cs:

image

Click OK, and the Portable project should now contain files named MainPage.xaml and MainPage.xaml.cs:

image

Initially, MainPage.xaml contains some basic XAML consisting of a ContentPage and a Label:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyAwesomePortableApp.MainPage">
    <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

To make MainPage.xaml the page that’s shown when the app starts, edit the App constructor in App.cs to look like this:

public App()
{
    MainPage = new MainPage();
}

Now you can build your UI declaratively by editing MainPage.xaml. There is no designer support at the moment, and no IntelliSense either, but look for that to change in the future.

Xamarin XAML is similar to Microsoft XAML, but not identical. In fact, there are enough differences to frustrate someone who knows Microsoft XAML pretty well. Xamarin XAML comes with its own set of visual elements. While many of these elements have analogs in the Microsoft world (Xamarin’s StackLayout is very similar to Microsoft’s StackPanel, for example), some do not, and Shape primitives such as Rectangle and Ellipse don’t even exist. Moreover, a lot of the properties Microsoft XAML developers are familiar with have been renamed in Xamarin XAML or simply do not exist at all. For example, the DataContext property in Microsoft XAML is called BindingContext in Xamarin, and the Margin property present on every visual element in Microsoft XAML is missing in Xamarin. But aside from the different elements in the two platforms, the XAML dialect is the same in both. Both support the property-element syntax, for example, and both support data binding and the {Binding} markup extension.

Xamarin divides the elements available to Xamarin Forms apps into four groups. The first is the set of elements representing pages:

The second group allows you to arrange elements on a page and are collectively known as “Layouts.” They’re analogous to Grid, StackPanel, Canvas, and other layout controls in Microsoft XAML:

Layouts

The third group, known as “Views,” contains the controls that serve as the building blocks for interactive, touch-friendly XAML UIs. It currently includes ActivityIndicator, BoxView, Button, DatePicker, Editor, Entry, Image, Label, ListView, Map, OpenGLView, Picker, ProgressBar, SearchBar, Slider, Stepper, Switch, TableView, TimePicker, and WebView. Here’s how a DatePicker control looks in Windows Phone, Android, and iOS:

image

The fourth and final group contains “Cells:” controls that represent items displayed in ListViews and TableViews. Its members include EntryCell, ImageCell, SwitchCell, TextCell, and ViewCell. ViewCells can be used in data templates to specify custom renderings for items in items controls, while the other Cell types provide canned implementations of common items.

The taxonomy of elements at your disposal will undoubtedly grow in the future, and already third-party control vendors are offering elements of their own to help you build rich cross-platform XAML UIs. But for now, in Xamarin Forms 1.3, this is what you have to work with. And it is a subset of these elements – specifically, ContentPage, Grid, Entry, and Button – that I used to build the calculator UI.

CalculatorPage

Here are the contents of CalculatorPage.xaml (the main page) in the RPN Calculator app, minus a few lines of XAML used to tweak the UI on different platforms:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFormsRPNCalculator.CalculatorPage"
             xmlns:local="clr-namespace:XFormsRPNCalculator;assembly=XFormsRPNCalculator"
             Padding="16">

  <Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition Height="1.5*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
      
    <ContentView Padding="8" Grid.Row="0" Grid.ColumnSpan="4">
      <Label x:Name="Output" Text="{Binding Output}" Grid.Column="0" XAlign="End">
      </Label>
    </ContentView>

    <Button Text="±" Grid.Row="1" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="±" />
    <Button Text="EXP" Grid.Row="1" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="EXP" />
    <Button Text="STO" Grid.Row="1" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="STO" />
    <Button Text="RCL" Grid.Row="1" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="RCL" />

    <Button Text="ENTER" Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="ENTER" />
    <Button Text="FIX" Grid.Row="2" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="FIX" />
    <Button Text="CLX" Grid.Row="2" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="CLX" />

    <Button Text="-" Grid.Row="3" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="-" />
    <Button Text="7" Grid.Row="3" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="7" />
    <Button Text="8" Grid.Row="3" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="8" />
    <Button Text="9" Grid.Row="3" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="9" />

    <Button Text="+" Grid.Row="4" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="+" />
    <Button Text="4" Grid.Row="4" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="4" />
    <Button Text="5" Grid.Row="4" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="5" />
    <Button Text="6" Grid.Row="4" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="6" />

    <Button Text="x" Grid.Row="5" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="x" />
    <Button Text="1" Grid.Row="5" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="1" />
    <Button Text="2" Grid.Row="5" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="2" />
    <Button Text="3" Grid.Row="5" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="3" />

    <Button Text="÷" Grid.Row="6" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="÷" />
    <Button Text="0" Grid.Row="6" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="0" />
    <Button Text="." Grid.Row="6" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="." />
    <Button Text="DEL" Grid.Row="6" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="DEL" />
  </Grid>
</ContentPage>

This looks a LOT like Microsoft XAML, but there are a few notable differences:

  • I wanted some padding around the Label control that serves as the calculator’s output window, but the Xamarin Label control has neither a Padding property nor a Margin property. So I wrapped it in a ContentView, which does have a Padding property. Wrapping controls in other controls simply to control spacing is, unfortunately, all too common in Xamarin Forms.
  • In Microsoft XAML, one would use HorizontalAlignment=”Right” to right-align a TextBlock in a Grid cell. In Xamarin XAML, you use XAlign=”End” to do the same for a Label control.
  • Microsoft Button controls have a Content property that allows you to put just about anything you want on the face of a Button. Xamarin Buttons have a Text property but no Content property, so they’re only intended to show text.
  • In Microsoft XAML, I could avoid the redundant assignments to the Buttons’ Text and CommandParameter properties using {RelativeSource Self}. But while Xamarin supports {Binding}, it doesn’t support {RelativeSource}.

Despite these minor differences, it’s pretty remarkable that a UI can be defined this way, compiled into a Portable Class Library, and rendered on iOS, Android, and Windows Phone. That’s not to say the UI will look perfect on every platform. The reality is that you’ll inevitably need to tweak the UI for individual platforms. Xamarin Forms gives you an awesome way to do that. It’s called OnPlatform.

Tweaking the UI with OnPlatform

OnPlatform is the key to using shared XAML files to make a UI look good on every platform. In the example in the previous section, I added Padding=”16” to the ContentPage to put a little space between the edge of the screen and the UI. Applied this way, the Padding value is applied to every platform.

But let’s say you wanted 8 pixels of padding on iOS, 16 on Android, and 32 on Windows Phone. Here’s how you’d accomplish that:

<ContentPage.Padding>
  <OnPlatform x:TypeArguments="Thickness" iOS="8" Android="16" WinPhone="32" />
</ContentPage.Padding>

OnPlatform is a generic class that has properties named iOS, Android, and WinPhone, all of type T (as in OnPlatform<T>). You don’t have to specify values for all three. If you’re happy with the default ContentPage padding for iOS and Android, you could simply write:

<ContentPage.Padding>
  <OnPlatform x:TypeArguments="Thickness" WinPhone="32" />
</ContentPage.Padding>

Get it? With OnPlatform, you can specify platform-specific values in a shared XAML file. Here’s CalculatorPage.xaml again, this time with all the XAML, including the platform-specific stuff:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFormsRPNCalculator.CalculatorPage"
             xmlns:local="clr-namespace:XFormsRPNCalculator;assembly=XFormsRPNCalculator"
             Padding="16">

  <ContentPage.BackgroundColor>
    <OnPlatform x:TypeArguments="Color" iOS="#fff0f0f0" Android="Black" />
  </ContentPage.BackgroundColor>

  <ContentPage.Resources>
    <ResourceDictionary>
      <Style TargetType="Button">
        <Setter Property="BorderColor">
          <Setter.Value>
            <OnPlatform x:TypeArguments="Color" WinPhone="#FF404040" />
          </Setter.Value>
        </Setter>
        <Setter Property="BackgroundColor">
          <Setter.Value>
            <OnPlatform x:TypeArguments="Color" iOS="White" WinPhone="#FF303030" />
          </Setter.Value>
        </Setter>
      </Style>
    </ResourceDictionary>
  </ContentPage.Resources>

  <Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition Height="1.5*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    
    <Grid.RowSpacing>
      <OnPlatform x:TypeArguments="x:Double" iOS="8" WinPhone="-10" />
    </Grid.RowSpacing>

    <Grid.ColumnSpacing>
      <OnPlatform x:TypeArguments="x:Double" iOS="8" WinPhone="-10" />
    </Grid.ColumnSpacing>

    <ContentView Padding="8" Grid.Row="0" Grid.ColumnSpan="4">
      <Label x:Name="Output" Text="{Binding Output}" Grid.Column="0" XAlign="End">
        <Label.Font>
          <OnPlatform x:TypeArguments="Font" iOS="36" Android="48" WinPhone="56" />
        </Label.Font>
      </Label>
    </ContentView>

    <Button Text="±" Grid.Row="1" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="±" />
    <Button Text="EXP" Grid.Row="1" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="EXP" />
    <Button Text="STO" Grid.Row="1" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="STO" />
    <Button Text="RCL" Grid.Row="1" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="RCL" />

    <Button Text="ENTER" Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="ENTER" />
    <Button Text="FIX" Grid.Row="2" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="FIX" />
    <Button Text="CLX" Grid.Row="2" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="CLX" />

    <Button Text="-" Grid.Row="3" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="-" />
    <Button Text="7" Grid.Row="3" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="7" />
    <Button Text="8" Grid.Row="3" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="8" />
    <Button Text="9" Grid.Row="3" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="9" />

    <Button Text="+" Grid.Row="4" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="+" />
    <Button Text="4" Grid.Row="4" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="4" />
    <Button Text="5" Grid.Row="4" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="5" />
    <Button Text="6" Grid.Row="4" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="6" />

    <Button Text="x" Grid.Row="5" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="x" />
    <Button Text="1" Grid.Row="5" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="1" />
    <Button Text="2" Grid.Row="5" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="2" />
    <Button Text="3" Grid.Row="5" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="3" />

    <Button Text="÷" Grid.Row="6" Grid.Column="0" Command="{Binding CalculatorCommand}" CommandParameter="÷" />
    <Button Text="0" Grid.Row="6" Grid.Column="1" Command="{Binding CalculatorCommand}" CommandParameter="0" />
    <Button Text="." Grid.Row="6" Grid.Column="2" Command="{Binding CalculatorCommand}" CommandParameter="." />
    <Button Text="DEL" Grid.Row="6" Grid.Column="3" Command="{Binding CalculatorCommand}" CommandParameter="DEL" />
  </Grid>
</ContentPage>

The first instance of OnPlatform customizes the page’s background color on iOS and Android. The next changes the default border color on Buttons in Windows Phone and the default background color on Buttons in iOS and Windows Phone. (As of Xamarin Forms 1.3, Xamarin XAML supports styles just as Microsoft XAML does. It even supports default styles, also known as implicit styles, which are defined by omitting a style’s x:Key attribute.) The OnPlatforms applied to the Grid’s RowSpacing and ColumnSpacing properties reduce the whitespace between Buttons on Windows Phone. Incidentally, RowSpacing and ColumnSpacing are examples of how Xamarin XAML sometimes improves on Microsoft XAML. Grid has no such properties in Microsoft’s XAML runtimes. Once you get used to these properties in Xamarin, you’ll use them time and again.

Lifecycle Events

One of the most important – and sometimes difficult – aspects of writing a mobile app is dealing with app lifetime. On Windows Phone, an app is “deactivated” when it leaves the foreground. A few seconds after it’s deactivated, it’s suspended – all threads in the process are taken off the CPU and kept off until the app returns to the foreground. While an app is suspended, the operating system can terminate it at any time in order to conserve resources. Suspension is deterministic, but termination is not. That means you have to assume that an app will be terminated whenever it’s deactivated, and be prepared to restore the app to its former state if it’s reactivated – even if the operating system had to launch a whole new instance of the app.

The issue of saving and restoring state in order to create the illusion that a terminated app wasn’t really terminated isn’t unique to Windows Phone. Android and iOS developers have to code for this, too, although the mechanisms for doing so (and the steps required to preserve an app’s state) vary on different platforms.

Xamarin Forms 1.3 adds three virtual methods to the Application class to help developers respond to lifecycle events in a platform-agnostic manner:

  • OnStart, which is called when an app is launched or relaunched following termination
  • OnSleep, which is called when the app leaves the foreground, or is “deactivated” in Windows Phone parlance
  • OnResume, which is called when the app returns to the foreground after being deactivated (but not if the app was relaunched)

In addition, Xamarin Forms 1.3 adds a property named Properties to the Application class to serve as a persistent state bag for data you want to preserve if the app is terminated. In a simple case, assume your app has a single page that hosts a WebView control, and when the user switches away from the app, the WebView is showing content at http://developer.xamarin.com/guides/cross-platform/xamarin-forms/ – that is, the WebView’s Source property is “http://developer.xamarin.com/guides/cross-platform/xamarin-forms/.” When the app is deactivated, you want to preserve that value so you can restore it when the app is reactivated. Here’s the code in App.cs’s App class to do that, assuming the page is an instance of MainPage and you’ve added a Source property to MainPage that provides the application with read/write access to the WebView’s Source property:

protected override void OnStart()
{
    // When the app starts, retrieve the WebView URL from Application.Properties
    // and assign it to the WebView control in MainPage
    if (Application.Current.Properties.ContainsKey("URL"))
        ((MainPage)MainPage).Source = (string)Application.Current.Properties["URL"];
}

protected override void OnSleep()
{
    // When the app is deactivated, save the URL of the page displayed in the WebView
    // to Application.Properties
    string url = ((MainPage)MainPage).Source;
    Application.Current.Properties["URL"] = url;
}

That’s relatively simple and straightforward, and it works cross-platform. Values you write to the Application.Properties dictionary are serialized into persistent storage before the app is suspended, and deserialized and made available to the app the next time it starts.

My RPN calculator uses a similar approach to preserving state. (After all, you don’t want to get 50 keystrokes into a calculation and then lose your work when you switch over to check an e-mail or take an incoming call.) I wrote a helper class named CalculatorState to store everything about the calculator’s internal state. The only problem was that Application.Properties was designed to store primitive values such as strings and integers, but not instances of custom classes. (Under the hood, Xamarin Forms uses DataContractSerializer to serialize and deserialize the contents of Application.Properties, and DataContractSerializer can handle custom types through [KnownType] attributes. Alas, you can’t get to the DataContractSerializer to make it aware of known types.) I could have replaced the default serializer with one of my own, but I instead chose to serialize CalculatorState instances into JSON strings and write those strings to Application.Properties. Here’s the relevant code in App.cs:

protected override void OnStart()
{
    if (Application.Current.Properties.ContainsKey(_key))
    {
        string state = (string)Application.Current.Properties[_key];
        _cvm.SetState(Deserialize<CalculatorState>(state));
    }
}

protected override void OnSleep()
{
    string state = Serialize<CalculatorState>(_cvm.GetState());
    Application.Current.Properties[_key] = state;
}

_cvm is a reference to the view-model (an instance of CalculatorViewModel managed by the current Application instance), and Serialize and Deserialize are helper methods implemented elsewhere in App.cs.

More to Come

It’s cool to write an app in XAML and C# and see it come alive on iPhones, Android phones, and other devices. But you can imagine that Xamarin Forms has much more to offer than what was covered here. You need to know, for example, how to write multipage apps, how to use ListView and other cool Xamarin Forms controls, how to interact with services, and how to use custom renderers to enact deeper UI customizations. I’ll cover all this and more in future blog posts. In the meantime, check out the Xamarin Forms documentation on the Xamarin Web site, and keep an eye on the Wintellect DevCenter for more articles on Xamarin and Xamarin Forms. And if you plan to be in London in May, make plans to join me at the Software Design & Development conference. I’ll be doing a session there on Xamarin Forms and will have lots of cool source code to share.

Need Xamarin Help?

Xamarin Consulting  Xamarin Training

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X