0 Comments

StorageImage

A lot of applications have to persist application data or state. When developing mobile applications with C# such as for Windows or with Xamarin for iOS and Android it is a common approach to share your business logic and backend implementations in the Portable Class Library (PCL). In this blog post we’ll look at how we can also implement storage within the PCL and therefore will only need to implement the storage services once. We will be focusing on the following topics:

  1. Setting up the project
  2. Storing and loading objects to files
  3. Storing/using binary data such as images

So lets start off by setting up the project. I’ll be demonstrating the sample with a Xamarin.Forms project as it allows me to quickly develop, deploy and test an app on all three major mobile platforms. But as the code is in the PCL you can use the exact same approach to implement the system in Windows Store, WPF etc. applications.

Setting up the project

Lets create an app that lists Companies by name, URL and displays the company logo. To do this we will create a view that will display the content as follows:

<?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="XamarinFormsOfflineStorage.Views.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Text="Refresh" Command="{Binding UpdateCompaniesCommand}"></Button>
<ListView ItemsSource="{Binding Companies}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell Text="{Binding Name}" ImageSource="{Binding ImageUri}" Detail="{Binding ImageDescription}"></ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ActivityIndicator Grid.Row="1" IsRunning="{Binding IsLoadingData}"></ActivityIndicator>
</Grid>
</ContentPage>

The data is provided by a View Model that is based upon the MVVM Light framework by Laurent Bugnion. I wrote a post a while ago on how to get started with MVVM Light and Xamarin.Forms.

public class MainViewModel:ViewModelBase
{
private readonly ICompanyService _companyService;
private bool _isLoadingData;

public MainViewModel(ICompanyService companyService)
{
if (companyService == null) throw new ArgumentNullException("companyService");
_companyService = companyService;

Companies = new ObservableCollection<Company>();
IsLoadingData = false;
UpdateCompaniesCommand = new RelayCommand(UpdateCompanies, () => !IsLoadingData);
}

public bool IsLoadingData
{
get { return _isLoadingData; }
set
{
if (value == _isLoadingData) return;
_isLoadingData = value;
RaisePropertyChanged(() => IsLoadingData);
}
}

public ObservableCollection<Company> Companies { get; set; }

public ICommand UpdateCompaniesCommand { get; set; }

public async Task Init()
{
await UpdateCompaniesList();
}

private async void UpdateCompanies()
{
IsLoadingData = true;

await _companyService.UpdateCompanies();
await UpdateCompaniesList();

IsLoadingData = false;
}

private async Task UpdateCompaniesList()
{
var companies = await _companyService.GetCompanies();

Companies.Clear();

foreach (var company in companies)
{
Companies.Add(company);
}
}
}

Which calls a CompanyService that calls the backend:

// ...

public async Task UpdateCompanies()
{
// URL should point to where your service is running
const string uri = "http://offlinestorageserver.azurewebsites.net/api/values";
var httpResult = await _httpClient.GetAsync(uri);
var jsonCompanies = await httpResult.Content.ReadAsStringAsync();

var companies = JsonConvert.DeserializeObject<ICollection<Models.Company>>(jsonCompanies);
_companies = companies;
}

// ...

And provides a list of companies:

public IEnumerable<Models.Company> GetCompanies()
{
return _companies;
}

Now lets look on how we can store this list to the “disk” and display the information even if the app is started when there is no connection to the backend.

Enabling storage access in the PCL

Thanks to Daniel Plaisted accessing the file storage from within the PCL of your applications is actually really easy. All that is left to do for us is installing the NuGet package PCL Storage. Ensure that you install it not only for the PCL but only for the platforms you are targeting with your app:

PclStorageNugetInstall

Before we store lets just still quickly have a look at where we actually want to store the files. The PCL storage provides a start location which can be accessed by calling the FileSystem.Current.LocalStorage property. This will return an IFolder object which can be allows navigating to further folders by invoking the GetFolder method, alternatively the CreateFolder method can also be used with the collision option OpenIfExists, I generally use the second approach as it allows to write less code. So if we want to store our data in a folder within the root location of the local storage it would be done as follows:

private static async Task<IFolder> NavigateToFolder(string targetFolder)
{
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.CreateFolderAsync(targetFolder,
CreationCollisionOption.OpenIfExists);

return folder;
}

As you can see the PCL Storage embraces the Async/Await pattern nicely and therefore will not block your app i.e. UI when working against the file system. Now lets get down to storing some data.

Persist an object

Now lets first store the list of objects we receive from our service into a file. As I’m already using JSON.Net for deserializing the data that comes from our service I’ll be using this library to serialize our objects to a JSON string and then store the now text data to a file in the SerializeCompanies method:

private static async Task SerializeCompanies(IFolder folder, ICollection<Models.Company> companies)
{
IFile file = await folder.CreateFileAsync(CompaniesFileName, CreationCollisionOption.ReplaceExisting);
var companiesString = JsonConvert.SerializeObject(companies);
await file.WriteAllTextAsync(companiesString);
}

As you can see files are created similarly to folders but differ in the collision option. It generally is a generally easier to handle merging of data in the C# memory world itself (given that the list is not to large for this) and then simply overwriting the preexisting cache.

Loading the data object

We can now update the GetCompanies method to return the list when we call it.

public async Task<IEnumerable<Models.Company>> GetCompanies()
{
return _companies ?? (_companies = await ReadCompaniesFromFile());
}

Once the data has been persisted by the website we do no longer require an internet connection to present the user with the information. And we can simply read them from a file as in ReadCompaniesFromFile:

private async Task<IEnumerable<Models.Company>>  ReadCompaniesFromFile()
{
var folder = await NavigateToFolder(CompaniesFolder);

if ((await folder.CheckExistsAsync(CompaniesFileName)) == ExistenceCheckResult.NotFound)
{
return new List<Models.Company>();
}

IFile file = await folder.GetFileAsync(CompaniesFileName);
var jsonCompanies = await file.ReadAllTextAsync();

if (string.IsNullOrEmpty(jsonCompanies)) return new List<Models.Company>();

var companies = JsonConvert.DeserializeObject<IEnumerable<Models.Company>>(jsonCompanies);

return companies;
}

Now the object data is persisted but we haven’t yet stored the images which is not text data but binary data. So lets see how we can store images to the file system.

Store binary data

To store the images we will have to get the images and store the binary data from the web to a file. This is done using the file stream of the opened file in the StoreImagesLocallyAndUpdatePathmethod:

private async Task StoreImagesLocallyAndUpdatePath(IFolder folder, IEnumerable<Models.Company> companies)
{
foreach (var company in companies)
{
var file = await folder.CreateFileAsync(company.Name + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var fileHandler = await file.OpenAsync(FileAccess.ReadAndWrite))
{
var httpResponse = await _httpClient.GetAsync(company.ImageUri);
byte[] imageBuffer = await httpResponse.Content.ReadAsByteArrayAsync();
await fileHandler.WriteAsync(imageBuffer, 0, imageBuffer.Length);

company.ImageUri = file.Path;
}
}
}

Streams should always be disposed or else memory leaks will occur so the stream is wrapped in a using block. For storing the binary data we download the image via the URL provided and read the content into a byte array which allows us to easily pass it into the stream so it can get stored. Finally we replace the ImageUri data in the POCO (Plain Old CLR Object) before it gets serialized.

I recommend that you use the file endings according to the data you are storing. Certain containers rely on the information so as long as the good practice is kept up we are not running the risk of having to debug a strange error of information not showing up on the screen.

Loading images

Now we could load the images back into memory but as images are somewhat a special case the local path / ImageUri alone is enough to be set in the image control. So we actually do not have to change any code in the UI or add any additional handling as the image control will simply now load the image from the local storage.

Conclusion

In this post we saw how we can setup our projects to store files directly out of the PCL. We stored a data object i.e. text data to a file and proceeded to store an image/binary data. I think a big thank you is due to Daniel Plaisted as his work really streamlines persisting data with from the PCL.

You can find the entire code on GitHub.

References

Title Image by Dr. Hannes Grobe under Creative Commons V3

8 Comments

WCFXamarinTitleLogo

Windows Communication Foundation (WCF) used to be the way how web services were created in .Net. Allegedly it comes at no surprise that many backend services are implemented with WCF and therefore if you are in the business of writing mobile clients may face the task of integrating such a service. In this post we will look at how a WCF service can be integrated into a Xamarin.Forms app and how Begin/End async methods can be wrapped into task based async/await methods which are the defacto standard since C# 5/.Net 4.5.

In this blog post we will look at the following:

  1. Looking WCF web service that can run on IIS or Azure
  2. Creating the Xamarin.Forms App
    1. Add UI for interaction
    2. Add service reference in the Portable Class Library (PCL)
  3. Mapping to the new async/await model

The basic setup

Lets first have a look at how the app and the web service are setup before we do the final wiring up of the service.

Looking at the WCF web service

The WCF service I’m using for this sample code, which you can find as usual on GitHub, is a WCF Application. A WCF Application can run on IIS and be easily deployed to Azure which makes it perfect for getting up and running in no time without having to mess with IIS Express Firewall settings.

The service we will be integrating has a single method which will take an int and return a string, here is the interface definition:

[ServiceContract]
public interface IWcfService
{
[OperationContract]
string GetData(int value);
}

And the implementation is equally simple:

public class WcfService : IWcfService
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}

So as you can see the service method GetData takes an int wraps it in a string and will send it back to the caller. Now lets have a look at the client and the UI.

Xamarin.Forms project setup

Now on the client we will setup a XAML based Xamarin.Forms application with a PCL as core library. The app will be a single page app that displays a Picker, Button and Labelcontrol which will look like this on XAML:

<?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="WcfIntegrationXamarinForms.View.MainPage">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<Picker x:Name="NumberPicker" SelectedIndex="{Binding SelectedNumberIndex}">
<Picker.Items>
<x:String>1</x:String>
<x:String>2</x:String>
<x:String>3</x:String>
<x:String>4</x:String>
<x:String>5</x:String>
<x:String>6</x:String>
<x:String>7</x:String>
<x:String>8</x:String>
<x:String>9</x:String>
<x:String>10</x:String>
</Picker.Items>
</Picker>
<Button Text="Submit" Command="{Binding SubmitCommand}"></Button>
<ActivityIndicator IsRunning="{Binding IsCallingWebservice}"></ActivityIndicator>
<Label Text="{Binding Response}" />
</StackLayout>
</ContentPage>

Notice that the Picker does not allow to set the Items programmatically and only provides the SelectedIndex to get information on the selected item. Now at the back of the view we will be using a ViewModel based on MVVM Light, to which you can find a basic introduction here. The view model manages the inputs from the view calls the IWcfServiceWrapper and pushes the result back to the UI. Here is the implementation of the View Model:

public class MainViewModel : ViewModelBase
{
private readonly IWcfServiceWrapper _wcfServiceWrapper;
private string _response;
private readonly IList<string> _numbers;
private bool _isCallingWebservice;

/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IWcfServiceWrapper wcfServiceWrapper)
{
if (wcfServiceWrapper == null) throw new ArgumentNullException("wcfServiceWrapper");
_wcfServiceWrapper = wcfServiceWrapper;

_numbers = new List<string> {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
Response = "Pick a number and click submit";
SubmitCommand = new RelayCommand(GetResponseAsync, () => CanGetResponse);
CanGetResponse = true;
}

private async void GetResponseAsync()
{
CanGetResponse = false;
IsCallingWebservice = true;

Response = await _wcfServiceWrapper.GetDataAsync(Int32.Parse(_numbers[SelectedNumberIndex]));

CanGetResponse = true;
IsCallingWebservice = true;
}

public int SelectedNumberIndex { get; set; }

public bool CanGetResponse { get; set; }

public ICommand SubmitCommand { get; set; }

public bool IsCallingWebservice
{
get { return _isCallingWebservice; }
set
{
if (value == _isCallingWebservice) return;
_isCallingWebservice = value;
RaisePropertyChanged(() => IsCallingWebservice);
}
}

public string Response
{
get { return _response; }
set
{
if (_response == value) return;
_response = value;
RaisePropertyChanged(() => Response);
}
}
}

We simply implement the command which enables the ActivityIndicator to show a progress bar while we are waiting for our response.

Integrating the service

We will integrate the WCF service in the PCL which will allow us to use the interface for each platform. This approach is also valid when you develop for one single platform such as Windows (Phone), Android or iOS, so I really recommend you choose to implement your service in a PCL even if for now you are only targeting one platform. Adding WCF services i.e. creating the proxy classes and calls has always been a very trivial process and hasn’t changed in the modern world. Expand the PCL project, right click on References and select Add Service Reference…enter the URL of your web service and click OK.

AddServiceReference

This will generate all the necessary proxy classes and definitions so you can call the Webservice. Unfortunately though all the asynchronous are implemented with the Begin/End asynchronous pattern. Luckily we can easily wrap those calls and use the newer async/await model of asynchronous programming with C#.

Mapping to the new async/await model

With the Task library we get the TaskFactoryclass which has a FromAsync method which lets us wrap Begin/End async methods into a single awaitable task based asynchronous call. So we can add a WcfServiceWrapper.cs to our portable project which wraps the call as follows:

public class WcfServiceWrapper:IWcfServiceWrapper
{
private IWcfService _wcfService;

public WcfServiceWrapper(IWcfService wcfService)
{
if (wcfService == null) throw new ArgumentNullException("wcfService");

_wcfService = wcfService;
}

public async Task<string> GetDataAsync(int number)
{
Task<string> getDataTask = new TaskFactory().FromAsync<int,string>(_wcfService.BeginGetData, _wcfService.EndGetData, number, null, TaskCreationOptions.None);
return await getDataTask;
}
}

Conclusion

We looked at how a simple WCF service can be integrated in a Xamarin.Forms mobile app. Further the post shows you how you can wrap the Begin/End asynchronous pattern into todays async/await task based async pattern.

You can find the entire project on GitHub.

This post was originally posted on the Noser Blog.

7 Comments

MvvmLightNavigationTitle

I wrote this post a couple of years ago and while the implementation bellow worked for me in the beginning, I tended to reach it's limitation rather quickly in larger apps. So I encourage you to check out an updated version of the Navigation Service in one of my later posts.

Working with Model View ViewModel (MVVM) really enables you to reuse as much code as possible between platforms. For getting started with MVVM Light and Xamarin.Forms make sure to checkout my post on the topic. In this post I would really like to dive into another topic of MVVM Light namely the navigation service. Navigating between pages is normally done on by invoking a platform dependent API call, calling these Interfaces in your View Model usually is though of as bad design as it tightly couples your View Model to the platform and therefore prevents sharing the VM across platforms. MVVM Light provides a Navigation Service that lets us invoke page navigations without coupling it to a platform.

Creating the application

With Xamarin.Forms you have two ways how to create your Application, Sharedand and Portable Class Library (PCL). I recommend using the PCL as it will allow to reuse the most amount of code when targeting other platforms such as .Net or Windows Store apps. When writing your UI with Xamarin.Forms you again have the option of writing your UI in C# aka code behind or use XAML to create your UIs. Again I choose the later as XAML provides a nice way of formatting your UI components and provides a natural way of interaction if you have a WPF, Silverlight or Windows Apps background.

The app will exist of three pages:

NavigationOverview

The first page contains a button which when selected navigates to the second page:

<?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="MvvmLightNavigation.XamarinForms.Views.FirstPage">
<Button Text="Navigate to second page" Command="{Binding NavigateCommand}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

The second page has a Text box and a button, the text box will be sent to the third page as parameter and the button is again used to trigger the navigation.

<?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="MvvmLightNavigation.XamarinForms.Views.SecondPage">
<Entry Placeholder="Please enter a parameter" Text="{Binding Paramter}" VerticalOptions="Center" HorizontalOptions="Center" />
<Button Text="Navigate to second page" Command="{Binding NavigateCommand}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

On the third page we have a label to display the navigation content. The button can be used instead of the back button (which on Android and Windows may be physical) to get back to the second page:

<?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="MvvmLightNavigation.XamarinForms.Views.ThirdPage">
<Label Text="{Binding ParameterText}" VerticalOptions="Center" HorizontalOptions="Center" />
<Button Text="Go back" Command="{Binding NavigateCommand}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Wiring up the navigation

First we will have setup an interface to the navigation stack of Xamarin.Forms, so lets write/copy&paste our NavigationService.cs class:

public class NavigationService : INavigationService
{
private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
private NavigationPage _navigation;

public string CurrentPageKey
{
get
{
lock (_pagesByKey)
{
if (_navigation.CurrentPage == null)
{
return null;
}

var pageType = _navigation.CurrentPage.GetType();

return _pagesByKey.ContainsValue(pageType)
? _pagesByKey.First(p => p.Value == pageType).Key
: null;
}
}
}

public void GoBack()
{
_navigation.PopAsync();
}

public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}

public void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
var type = _pagesByKey[pageKey];
ConstructorInfo constructor;
object[] parameters;

if (parameter == null)
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(c => !c.GetParameters().Any());

parameters = new object[]
{
};
}
else
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(
c =>
{
var p = c.GetParameters();
return p.Count() == 1
&& p[0].ParameterType == parameter.GetType();
});

parameters = new[]
{
parameter
};
}

if (constructor == null)
{
throw new InvalidOperationException(
"No suitable constructor found for page " + pageKey);
}

var page = constructor.Invoke(parameters) as Page;
_navigation.PushAsync(page);
}
else
{
throw new ArgumentException(
string.Format(
"No such page: {0}. Did you forget to call NavigationService.Configure?",
pageKey),
"pageKey");
}
}
}

public void Configure(string pageKey, Type pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
_pagesByKey[pageKey] = pageType;
}
else
{
_pagesByKey.Add(pageKey, pageType);
}
}
}

public void Initialize(NavigationPage navigation)
{
_navigation = navigation;
}
}

This code was written by Laurent Bugnion for his 2014 Evolve talk. To use the navigation service the pages have to be registered as key value pairs where the key is a representative String and the value is the page itself, this is done in the Locator.cs class:

public const string FirstPage = "FirstPage";
public const string SecondPage = "SecondPage";
public const string ThirdPage = "ThirdPage";

Making the Keys public will ensure that other classes i.e. the ViewModels will be able to invoke the Navigation Servicewithout running the risk breaking navigation when Keys are getting renamed due to refactoring. Next setup the navigation service in the App.cs class:

public class App : Application
{
// ...

public App()
{
var nav = new NavigationService();
nav.Configure(Locator.FirstPage, typeof(FirstPage));
nav.Configure(Locator.SecondPage, typeof(SecondPage));
nav.Configure(Locator.ThirdPage, typeof(ThirdPage));
SimpleIoc.Default.Register<INavigationService>(() => nav);

var firstPage = new NavigationPage(new FirstPage());

nav.Initialize(firstPage);

//SimpleIoc.Default.Register<INavigationService>(() => nav);

MainPage = firstPage;
}

// ...
}

As you can see it’s simply matching the keys with the representing page.

The ViewModels

We could leave out the ViewModels and just invoke the navigation commands on the event handler in the code behind, but in most scenarios you will invoke the navigation from within the ViewModel as it will allow you to reuse the code even when you migrate from a Xamarin.Forms app to a Windows Store, Xamarin.iOS or Xamarin.Android stack. So lets create a View Model for each page.

The first ViewModel exists mainly out of the RelayCommand:

private readonly INavigationService _navigationService;
public FirstViewModel(INavigationService navigationService)
{
if (navigationService == null) throw new ArgumentNullException("navigationService");
_navigationService = navigationService;

NavigateCommand = new RelayCommand(() => { _navigationService.NavigateTo(Locator.SecondPage); });
}

public ICommand NavigateCommand { get; set; }

When the relay command is invoked the navigation is triggered and a push navigation will be executed. The second ViewModel offers a property that can be set and used as navigation parameter:

private readonly INavigationService _navigationService;
public SecondViewModel(INavigationService navigationService)
{
if (navigationService == null) throw new ArgumentNullException("navigationService");
_navigationService = navigationService;

NavigationCommand =
new RelayCommand(() => { _navigationService.NavigateTo(Locator.ThirdPage, Parameter ?? string.Empty); });
}

public ICommand NavigationCommand { get; set; }
public string Parameter { get; set; }

Passing a parameter is done easily as you can see. Note that if you pass null to the navigation service the default constructor will be invoked, which may not be what you intend to do. Receiving the parameter is done via the constructor on the code behind of the third page:

public partial class ThirdPage : ContentPage
{
public ThirdPage(string parameter)
{
InitializeComponent();
var viewModel = App.Locator.Third;
BindingContext = viewModel;

viewModel.ParameterText = string.IsNullOrEmpty(parameter) ? "No parameter set" : parameter;
}
}

Within the constructor the parameter is passed to the ViewModel. The third ViewModel is very similar to the second ViewModel:

private readonly INavigationService _navigationService;
private string _parameterText;

public ThirdViewModel(INavigationService navigationService)
{
if (navigationService == null) throw new ArgumentNullException("navigationService");
_navigationService = navigationService;

NavigateCommand = new RelayCommand(() => { _navigationService.GoBack(); });
}

public string ParameterText
{
get { return _parameterText; }
set
{
if (_parameterText == value) return;
_parameterText = value;
RaisePropertyChanged(() => ParameterText);
}
}

public ICommand NavigateCommand { get; set; }

The back navigation is also implemented within the command. You can either select the button or simply use the default navigation buttons according to the system your app is running on.

Retrieving the current PageKey

This function can come in quite handy if you need to know which page is currently displayed and inform your ViewModel accordingly. By overriding the OnAppearing method in the code behind of the SecondPage.xaml.csyou see how the information can be read out:

protected override void OnAppearing()
{
base.OnAppearing();
var currentPageKeyString = ServiceLocator.Current
.GetInstance<INavigationService>()
.CurrentPageKey;
Debug.WriteLine("Current page key: " + currentPageKeyString);
}

Now every time you navigate to or back to the second page the information will be printed to the debug console.

Conclusion

This post shows how you can use MVVM Lights navigation service to navigate between pages, passing parameters and getting the information on which page is currently being displayed to the user. Using the Navigation Service from MVVM Light provides a nice solution for abstracting the navigation layer within your Xamarin.Forms application and allows you to reuse the code if you decide to use the more powerful Xamarin.iOS, Xamarin.Android or Windows native UI pages.

You can find the entire code on GitHub.

References

http://www.mvvmlight.net/doc/nav1.cshtml

0 Comments

xamarin_forms

Writing cross platform native applications just got a lot easier with Xamarin.Forms. I really like the aspect of being able to write my UI in XAML. Though to be fair I just want to state that it is a XAML-dialect and does differ from the XAML controls you may know from Apps or WPF written for Windows (Phone).

The basics

To be able to write Xamarin.Forms applications at least an Indie license is required for Android and iOS. To add Windows Phone i.e. develop in Visual Studio a XYZ license is required. I'll be using Visual Studio for the next steps as my employee provides me with an Enterprise license for development. So first thing is to create a new Xamarin.Forms (PCL) project. This will create a solution with four projects. One for each platform and a core library i.e. the PCL.

Xamarin_forms_solution

Adding the XAML-page

the plattform projects all call the app.cs class which is located in the shared PCL library. This is the main starting point for any Xamarin.Forms Application. The originally generated code will crate a page and use code behind to genearte the code. So now lets add a XAML page to replace it:

Xamarin_forms_add_page 

It's XAML time

Now we can add our infamous "Hello World" message to the XAML.

<?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="HelloXamarinForms.HelloXamarinForms">
<Label Text="Hello Xamarin Forms" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Now all we need to do is use the XAML page instead of the pre-generated code behind site. This is done again within the app.cs class which we can find in the core PCL library, where we adjust the original main page from:

// Default RootPage
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label {
XAlign = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}
}
};

to:

MainPage = new HelloXamarinForms();

Now all we need to do is punch the good old F5 and et viola the app loads our XAML-"Hello world" message. So in conclusion yes you can write your views in XAML when using Xamarin.Forms. The names of the controls are different but the concepts behind the logic remains the same and therefore the same gains can be made.

HTH