Xamarin

Table of Contents

C#

General

Namespace

The namespace keyword is used to declare a scope that contains a set of related objects. To use/import a namespace we use the keyword using <namespace>. This will import everything in that namespace which can then be referenced as it was written inside that document, like import * from numpy or whatever in Python.

namespace SampleNamespace {
    class SampleClass {}

    interface SampleInterface {}

    struct SampleStruct {}

    enum SampleEnum {}

    delegate void SampleDelegate(int i);

    namespace SampleNamespace.Nested {
        class SampleClass2 {}
    }
}

And to use a namespace

using SampleNamespace;

class UseSampleClass {
    SampleClass sampleClass = new SampleClass();
}

Modifiers

Modifier Purpose
Access modifiers Specifies the declared accessibility of types and type members
abstract Class is intended only to be a base class of other classes
async Method, lambda expression, or anonymous function is asynchronous
const Value or field cannot be modified
event Declares an event
extern Method is implemented externally
override Provides a new implemetion of a virtual member inherited from a base class
partial Defines partial classes, structs and methods throughout the same assembly
readonly Declares a field that can only be assigned values as a part of the declaration or in the constructor of the class
sealed Specifies that a class cannot be inherited
virtual Method or accessor whose implementation can be changed by overriding a member in a derived class
volatile Field can be modified in the program by something such as the operating system, hardware, or a concurrently executing thread
static Declares a member that belongs to the type itself, instead of an instance of the typeclass. Can also have static class which means that the class /cannot be instantiaed.

Access modifiers

Public

Method or field is accesible by everything.

Private

Method or field is only accesible within the body of the class or struct in which they are declared.

Protected

Method or field is only accessible within the its class and by derived class instances.

More indept modifiers

partial

partial makes it possible to split the definition of a class or a struct, an interface or a method over multiple source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled.

Why?

  • Working on large projects, spreading a class over seperate files allows multiple programmers to work on the same class simultaneously.
  • When working with automatically generated source code, this allows us to add code to the class without having to recreate the source file.

There are several restrictions when working with partial classes.

class Container {
    partial class Nested {
        void Test() {}
    }

    partial class Nesten {
        void Test2() {}
    }
}
readonly

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introducted by the declaration can only occur as part of the declaration or in a constructor of the same class.

class Age {
    readonly int _year;

    Age(int year) {
        _year = year;
    }
    void changeYear() {
        // _year = 1967; --> Compile error
    }
}

Exception handling

Throw

throw is used to signal the occurence of an anomalous sitation (exception) during the program execution.

Remark: A thrown execption is an object whose class is derived from System.Exception.

public class ThrowTest
{

    static int GetNumber(int index)
    {
        int[] nums = { 300, 600, 900 };
        if (index > nums.Length)
        {
            throw new IndexOutOfRangeException();
        }
        return nums[index];

    }
    static void Main() 
    {
        int result = GetNumber(3);

    }
}
/*
    Output:
    The System.IndexOutOfRangeException exception occurs.
*/

Try-catch-finally

This works as you would expect. You use try { ... } to try something, then you catch potenial exceptions using the catch (Exception e) { ... }, and finally you do whatever needs to done finally { ... }.

Debugging

Writing to the debugging console can be done by simply using Debug.WriteLine(string) where Debug can be found in System.Diagnostics.

Getters and setters

In C# we can write getters and setters easily.

public string Name {get; set; }

The compiler will then auto-generate the equivalent simple implementation:

private string _name;

public string Name {
    get { return _name; }
    set { _name = value; }
}

.NET Framework

System

EventArgs

This class serves as the base class for all classes that represent event data. Source.

Assembly

"Assemblies are the building blocks of .NET Framework applications; they form the fundamental unit of deployment, version control, reuse, activation scoping, and security permissions. An assembly is a collection of types and resources that are built to work together and form a logical unit of functionality. An assembly provides the common language runtime with the information it needs to be aware of type implementations. To the runtime, a type does not exist outside the context of an assembly." Source: MSDN

An assembly is a file that is automatically generated by the compiler upon successful compilation of ever .NET application. It can either be a Dynamic Link Library (DLL) or an executable file. It is generated only once for an application and upon each subsequent compilation the assembly gets updated.

An Assembly contains Microsoft Intermediate Language (MSIL) code, which is similar to Java byte code. In the .NET language, it consists of metadata. Metadata enumerates the features of every "type" inside the assembly or the binary.

An assembly performs the following functions (in short):

  • Contains the common language runtime executes. MSIL code in a portable executable (PE) file will not be executed if it does not have an associated assembly manifest. Note that each assembly can have only one entry point (that is, DllMain, WinMain, or Main)
  • Forms a security boundary.
  • Forms a reference scope boundary
  • Forms a version boundary
  • Forms a deployment unit

Attributes

You can read a ton about attributes here.

Generally

Attributes are used within .NET for declarative programming. We can use attributes to define both design-level information (such as help file, URL for documentation) and run-time information (such as associating XML field with class field).

From what I understand, they're an attempt to improve upon the compiler directives from C. Remember the macro stuff? It allowed us to do something like this 1:

#if DEBUG
    doSomethingOnlyInDebugMode();
#else
    doSomethingInReleaseMode();
#endif

Instead, .NET allows us to do the following:

[Conditional("DEBUG")]
private void doSomethingOnlyInDebugMode();

private void doSomethingInReleaseMode();

public ClassName() {
    doSomethingInReleaseMode();

    doSomethingOnlyInDebugMode();
}

And the doSomethingOnlyInDebugMode() will only be executed in, you guessed it, debug mode!

Or stuff like this:

using System;
public class AnyClass 
{
    [Obsolete("Don't use Old method, use New method", true)]
    static void Old( ) { }

    static void New( ) { }

    public static void Main( ) 
    {
        Old( );
    }
}

Which will throw the following error when we compile

AnyClass.Old()' is obsolete: 'Don't use Old method,  use New method'

Custom attributes

You can also develop your own attributes.

A class that derives from the abstract class System.Attribute class, whether directly or indirectly, is an attribute class. The declaration of an attribute class defines a new kind of attribute that can be placed on a declaration. Thus, all we have to do is inherit from System.Attribute and we're done!

using System;

public class HelpAttribute : Attribute { }

[Help()]
public class SomeClass { }

Note: it's convetion to use Attribute as a suffix in attribute class names.

Attribute Identifiers

Suppose we want to place a Help attribute on an entire assembly. This can be done using the attribute identifier assembly, like this

[assembly: Help("this is a do-nothing assembly")]

The assembly identifier before the Help attribute explicitly tells the compiler that this attribute is attached to the entire assembly.

Possible identifiers are:

  • assembly
  • module
  • type
  • method
  • property
  • event
  • field
  • param
  • return

Asynchronized programming with Async and Await

By using async and await you can use resources in the .NET Framework or the Windows Runtime to create an asynchronous method almost as easily as you can create a synchronous method.

async Task<int> AccessTheWebAsync() {
    // You need to add a refecernece to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string> which means that when you 'await'
    // the task you'll get a string (urlContents)
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // ...

    string urlContents = await getStringTask;

    return urlContents.Length;
}

There are three things worth noting in the signature of AccessTheWebAsync:

  • The method has an async modifier
  • The return type is Task or Task<T> where the generic T defines the return type of the task
  • The method name ends in "Async"

GetStringAsync returns a Task<string>, ergo when we await we get a string representing the content of the url, which we later store in urlContents. Now, await suspends the function, which means that AccessTheWebSync can't continue until GetStringAsync is complete. But control is returned to the caller of AccessTheWebSync while we wait. Control is then brought back to AccessWebSync when getStringTask is complete. The string result is then retrieved from getStringTask and function keeps going.

Methods from .NET Framework 4.5 and the Windows Runtime contain methods that support async programming:

Application area Supporting APIs that contain async methods
Web access HttpClient, SyndicationClient
Working with files StorageFile, StreamWriter, StreamReader, XmlReader
WCF Programming Synchronous and Asychronous Opertaions

async

Use the async modifier to specify that a method, lambda expression or anonymous method is asynchronous. Using this modifier -> we have a async method.

public async Task<int> ExampleMethodAsyc() {
    // ...
}

Appendix

Syllabus

WCF = Windows Communication Foundation DLL = Dynamic-Link Library IL = Intermediate Language MSIL = Microsoft Intermediate Language PE = Portable Executable

Xamarin.Forms

Concepts

DependencyService

Overview

DependencyService allows you to call into platform-specific functionality from shared code. It's a dependency resolver. In practice, an interface is defined and the DependecyService finds the correct implementation of that interface from the various platforms.

How it works

Xamarin.Forms apps need three components to use DependencyService:

  • Interface The required functionality is defined by an interface in shared code.
  • Implementation for each platform Classes that implement the interface must be added to each platform object.
  • Registration of implementation Each implementing class must be registered with DependencyService via a metadata attribute. Registration enables DependencyService to find the implementing class and supply it in place of the interface at run time.
  • Call to DependencyService Shared code needs to explicitly call DependencyService to ask for implementations of the interface.

Platform projects without implementations will fail at runtime.

Example
public interface ITextToSpeech {
    void Speak (string text);  // interface members are public by default
}
[assembly: Xamarin.Forms.Dependency(typeof(TextToSpeechImplementation))]
namespace TextToSpeach.WinPhone {
    public class TextToSpeechImplementation : ITextToSpeech {
        public TextToSpeechImplementation( ) { };

        public async void Speak(string text) {
            SpeechSynthesizer synth = new SpeechSynthesizer();
            await synth.SpeakTextAsync(text);
        }
    }
}

Note: the dependency registration is performed at the namespace level.

Now that we've implemented the interface ITextToSpeech and registered its Windows implementation TextToSpeechImplementation, we can do

DependencyService.Get<ITextToSpeech>().Speak("Hello, World!");

Where DependencyService<T> will find the correct implementation of interface <T>.

Note: You must provide an implementation for every platform project. If no interface implementation is registered, then the DependencyService will be unable to resolve the Get<T> method at runtime.

ServiceLocator

BindableProperties

Overview

In Xamarin.Forms, the functionality of common language runtime (CLR) properties is extended by bindable properties. A BindableProperty is a special type of property, where the property's value is tracked by the Xamarin.Forms property system.

The purpose is to provide a property system that supports data binding, styles, templates, and values set through parent-child relationships.

In addition, BindableProperty can provide default values, validation of property values, and callbacks that monitor property changes.

Properties should be implemented as BindableProperty in order to support one or more of the following:

  • Acting as a valid target property for data binding
  • Setting the property through a Style
  • Providing a default property value that's different from the default for the type of the property
  • Validating the value of the property
  • Monitoring property changes
Creating and Consuming a Bindable Property

The process for creating a bindable property as follows:

  1. Create a BindableProperty instance with one of the BindableProperty.Create method overloads.
  2. Define property accessors for the BindableProperty instance.

Important: In order to create a BindableProperty instance, the containing class must derive from the BindableObject class.

At a minimum, an identifier must be specified when creating a BindableProperty, along with the following parameters:

  • The name of the BindableProperty
  • The type of the property
  • The type of the owning object
  • The default value of the property. The default value will be restored when ClearValue method is called on the BindableProperty.
public static readonly BindableProperty EventNameProperty =
    BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null);

This creates a BindableProperty instance named EventName, of type string. The property is owned by the EventToCommanderBehavior class, and has a default value of null.

Detecting Property Changes
public static readonly BindableProperty EventNameProperty =
  BindableProperty.Create (
    "EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)
{
  // Property changed implementation goes here
}

Data binding

Data binding is the process of connecting the UI and the business logic.

Data bindings connect properties of two objects, called the source and the target. In code two steps are required:

  1. Set the BindingContext property of the target to the source object.
  2. Set the Binding by calling SetBinding on the target object to bind a property of that object to a property of the source object.

Note: target property must be a bindable property, which means that the target object must derive from BindableObject.

All of the visual elements in the Xamarin.Forms namespace inherit from BindableObject class, which provide the methods SetBinding and BindingContext.

Note: BindingContex is set to null by default. So if we say wanted to refer to a field on the page itself, we would have to set BindingContext = this and refer in the XAML by {Binding FieldName}.

C# + XAML (Preffered)

This is a really good example from the Master Detail Page Xamarin Example.

C#

Inheritance from BindableObject exposes the methods SetBinding and BindingContext.

With C# we simply do the following:

var label = new Label();
label.SetBinding(Label.TextProperty, "Name");
label.BindingContext = new {Name = "John Doe", Company = "Xamarin"};

XAML

Here the Binding markup extension takes the place of SetBinding call and the Binding class.

We can set the binding using a StaticResource or x:Static markup extension, and even as the content of BindingContext property-element tags.

View-to-View

We can actually defined a view-to-view binding, that is link two views on the same page, as we do here.

<Slider x:Name="slider" />

<Label Text="ROTATION"
       BindingContext="{x:Reference Name=slider}"
       Rotation="{Binding Path=Value}" />

<Label BindingContenxt="{x:Reference slider}"
       Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}" />

Note: We can refer to the slider element using both Nameslider= and just slider.

Collections

ListView defines an ItemsSource property of type IEnumerable, and displays the items in that collection.

These items can be of any type. By default ListView uses the ToString method of each item to display that item. But we can display the items in the ListView collection in any way we want through the use ofa template, which involves a class that derives from Cell. Very often, we use the ViewCell class.

Say we have declared the local namespace to point to our project and we have a field in our namespace called NamedColor.All which returns all our NamedColor objects. These objects have a FriendlyName field which is simply the name of the color. We can then display the FriendlyName in a ListView as follows:

<ListView ItemsSource="{x:Static local:NamedColor.All}">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <ViewCell.View>
          <Label Text="{Binding FriendlyName}">
        </ViewCell.View>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

Events

We use the x:Name to create a reference to the XAML element, which is available in our View code. This item has different fields corresponding to the different events. These fields are Array s of EventHandler s. To create our own EventHandler, we simply append (using the += operator) our own function to this list of EventHandler s!

public partial class MainView : ContentPage
{
    public MainView ()
    {
        InitializeComponent ();
        // listView is a XAML ListView element with x:Name="listView"
        listView.ItemSelected += OnSelection;
    }

    void OnSelection(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.SelectedItem == null)
        {
            return;
        }

        DisplayAlert("Item selected", e.SelectedItem.ToString(), "Ok");
    }
}

We can also specify event handling in XAML

<Button Text="Click me breh"
        Clicked="OnClick">

where OnClick references a method on the class specifed by x:Class on the Page.

Custom Rendering

Within the ViewRenderer we can access the TView and TNativeView:

  • The TView can be referenced by Element
  • The TNativeView can be referenced by Control

There constraints for the second generic parameter to ViewRenderer :

Platform TNativeView
iOS UIKit.UIView
Android Android.View.Views
Windows Windows.UI.Xaml.FrameworkElement

XAML

Definitions

Pages

Xamarin.Forms uses the word Pages to refer to cross-platform mobile app screens.

The Page class Page is a visual element that occupies most or all of the screen and contains a single child. On specific OSes we have

OS Page represents
iOS View Controller
Android A page takes up the screen like an Activity
Windows Phone Page
Layouts

Xamarin.Forms Layout are used to compose user interface controls into logical structures.

The Layout class is a specialized subtype of View, which acts as a container for other Layout s or View s. It typically contains logic to set the position and size of child elements.

Views

Xamarin.Forms uses the word View to refer to visual objects such as buttons, labels or text entry boxes - which may be more commonly known as control of widgets.

See here for UI elements that are typically subclasses of View.

Cells

Xamarin.Forms cells can be added to ListView s and TableView s.

A Cell is a specialized element used for items in a table and describes how each item in a list should be drawn. Cell derives from Element.

See here for more info regarding Cell s.

Namespace declarations

Namespaces are declared by xmlns. We have the standard ones in Xamarin.Forms:

One for accessing Xamarin.Forms classes

xlmns="http://xamarin.com/schemas/2014/forms"

And another for the namespace for referencing tags and attributes intrinsic to XAML

xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

We can also reference our own code or the System namespace

xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
xmlns:sys="clr-namespace:System;assembly=mscorlib"

where mscorlib used to stand for "Microsoft Common Object Runtime Library", but now stands for "Multilanguage Standard Common Object Runtime Library".

Markup extensions

Sometimes properties must reference values defined elsewhere, or which might require processing by code at runtime. For these purposes, we use XAML markup extensions.

We call these extensions because they're backed by code in classes that implement IMarkupExtension.

One such method is to store values or objects in a No description for this link.

Another method is to use x:Static, which is what I prefer, to access a public static field, static property, or constant defined by a class or structure, or an enumeration member.

ResourceDictionary

To use a resource dictionary on a page, include a pair of Resources property-element tags.

Each item requires a x:Key, which specifies the dictionary key that we can use to access this resource. We then use the resource by Attribute"{StaticResource key}"= on an element. See 1.

StaticResource returns an object from a resource dictionary.

XAML also supports DynamicResource, which is a resource which may change during runtime.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

  <ContentPage.Resources>
    <ResourceDictionary>

      <LayoutUptions x:Key="horzOptions"
                     Alignment="Center" />

      <LayoutOptions x:Key="vertOptions"
                     Alignment="Center"
                     Expands="True" />

    </ResourceDictionary>
  </ContentPage.Resources>

  <Button Text="Hi"
          HorizontalOptions="{StaticResource horzOptions}"
          VerticalOptions="{StaticResource vertOptions}">

</ContentPage>
x:Static

I'd say this is my preferred way of doing things.

Here we explicitly reference static fields and enumeration members.

<Label Text="Hello, XAML!"
       VerticalOptions="{x:Static LayoutOptions.Start}"
       HorizontalTextAlignment="{x:Static TextAlignment.Center}"
       TextColor="{x:Static Color.Aqua}" />

And here we reference a static field from our own code. To do this though, we need to reference the namespace in our XAML file first. Say we have the class AppConstants, then

xmlns:local="clr-namespace:XamlSamples;assembl=XamlSamples"

And define our namespace in C#.

using System;
using Xamarin.Forms;

namespace XamlSamples {
    static class AppConstants {
        public static readonly Thickness PagePadding = new Thickness(5, Device.OnPlatform(20, 0, 0), 5, 0);

        public static readonly Font TitleFont = Font.SystemFontOfSize(Device.OnPlatform(35, 40, 50), FontAttributes.Bold);

        public static readonly Color BackgroundColor = Device.OnPlatform(Color.White, Color.Black, Color.Black);

        public static readonly Color ForegroundColor = Device.OnPlatform(Color.Black, Color.White, Color.White);
    }
}

Now, we simply reference our code using {x:Static local:AppConstants.fieldName}.

<Label Text="Hi"
       TextColor="{x:Static local:AppConstants.TextColor}"
       BackgroundColor="{x:Static local:AppConstants.BackgroundColor}"
       Font="{x:Static local:AppConstants.TitleFont}" />

Property-element

These are properties that we create inside their own tags. Instead of doing this

<Button Background="Blue" ... />

we can do

<Button>
  <Button.Background>
    "Blue"
  </Button.Background>
</Button>

which is what a property-element is!

Tutorials

Phoneword

Main Page

Xamarin.Forms uses XAML (XML-like language) to define the actual layout of the page. The MainPage class in MainPage.xaml defines the layout of the main page of the application. We then use the MainPage class in MainPage.xaml.cs to define the business logic that is executed when the user interacts with the 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="Phoneword.MainPage">
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness"
                iOS="20, 40, 20, 20"
                Android="20, 20, 20, 20"
                WinPhone="20, 20, 20, 20" />
  </ContentPage.Padding>
  <ContentPage.Content>
    <StackLayout VerticalOptions="FillAndExpand"
                 HorizontalOptions="FillAndExpand"
                 Orientation="Vertical"
                 Spacing="15">
      <Label Text="Enter a Phoneword:" />
      <Entry x:Name="phoneNumberText" Text="1-855-XAMARING" />
      <Button x:Name="translateButton" Text="Translate" Clicked="OnTranslate" />
      <Button x:Name="callButton" Text="Call" isEnabled="false" Clicked="OnCall" />
    </StackLayout>
  </ContentPage.Content>
</ContentPage>
using System;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace Phoneword {
  public partial class MainPage : ContentPage{
      string translatedNumber;

      public MainPage() {
          InitializeComponent();
      }

          void OnTranslate(object sender, EventArgs e) {
              translatedNumber = Core.PhonewordTranslator.ToNumber (phoneNumberText.Text);

              if (!string.IsNullOrWhiteSpace (translatedNumber)) {
                  callButton.IsEnabled = true;
                  callButton.Text = "Call " + translatedNumber;
              }
              else {
                  callButton.IsEnabled = false;
                  callButton.Text = "Call";
              }
          }

          async void OnCall (object sender, EventArgs e) {
              if (await this.DisplayAlert ("Dial a Number", "Would you like to call " + translatedNumber + "?", "Yes", "No")) {
                  var dialer = DependencyService.Get<IDialer> ();

                  if (dialer != null) {
                      dialer.Dial(translatedNumber);
                  }
              }
          }
      }
  }       

Master Detail Page

A Xamarin.forms MasterDetailPage is a page that has a master page for presentinglisting items, and a /detail page which is responsible for showing information about selected item. See here.

MasterPage.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="MasterDetailPageNavigation.MasterPage">
    <ContentPage.Content>
        <StackLayout>
            <ListView x:Name="listView">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ImageCell Text="{Binding Title}" ImageSource="{Binding IconSource}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

MasterPageItem.cs

// MasterPageItem.cs

using System;

namespace MasterDetailPageNavigation {
    public class MasterPageItem {
        public string Title { get; set; }

        public Type TargetType { get; set; }
    }
}

MasterPage.xaml.cs

// MasterPage.xaml.cs

using System.Collections.Generic;
using Xamarin.Forms;

namespace MasterDetailPageNavigation {
    public partial class MasterPage : ContentPage {
        public ListView ListView {get { return listView; }}

        public MasterPage () {
            InitializeComponent();

            // First we instatiate and populate the list that will be our ItemsSource
            var masterPageItems = new List<MasterPageItem> ();
            masterPageItems.Add(new MasterPageItem {
                    Title = "Contacts",
                    TargeType = typeof(ContactsPage)
                });
            masterPageItems.Add(new MasterPageItem {
                    Title = "About"
                    TargetType = typeof(AboutPage)
                });

            // Set the ItemsSource of the ListView element, which we reference using listView
            listView.ItemsSource = masterPageItems;
        }
    }
}

Then for the Xamarin.Forms MasterDetailPage stuff. We set the master-part of the MasterDetailPage by using the Master property on the MasterDetailPage as seen below. In the code-behind of MasterPage,

<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
                  x:Class="MasterDetailPageNavigation.MainPage">
    <MasterDetailPage.Master>
        <local:MasterPage x:Name="masterPage" />
    </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <NavigationPage>
            <x:Arguments>
                <local:ContactsPage />
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

Looking at this we might be a bit wierded out by the <NavigationPage><x:Arguments>... lines, but what it is actually doing is instatiating a NavigationPage object, which may either take no arguments or one argument of type Page. As we said, arguments, not properties! The XAML format allows us to pass arguments to the parent using the <Arguments> element, but we also need to reference the namespace of XAML, thus <x:Arguments>.

public class MainPage : MasterDetailPage {
    public MainPage() {
        InitializeComponents();
    }
}

Model-View-ViewModel (MVVM)

Old way - Singleton pattern

The Singleton pattern is convenient way to create and expose an instance of a class. Example 1 we show a class exposing a property following the Singleton pattern.

// Singleton Pattern implementation

public class DataService {
    private static DataService _instance;

    public static DataService Instance {
        get {
            return _instance ?? (_instance = new DataService());
        }
    }
}

Few thing to note about the code:

  • Constructor of class is private -> only way to create the instance is by using the Instance static property.
  • Instance is created on demand, which is generally a good thing, but sometimes we want the instance to be ready as soon as the application starts.
  • No way to delete the instance
  • Instances other than the main Instance property can be created, but each would require different accessors, either properties or methods.

A cleaner approach is to remove this infrastructure code from each class we implement and instead use an external object that acts like a cache for the instance we need in various parts of our application.

Inversion of Control and Dependency Injection

This is were Inversion of Control (IOC) comes in. The term means that the act of creating and keeping the instance is not the responsibility of the consuming class anymore, but is instead delegated to an external container.

The cached instances are often injected into the consumer class's constructor or made available through a property of the consumer, but this is not required. This is why we talk about Dependency Injection (DI).

DI is not necessary for IoC containers to work, but it is a convenient way to decouple the consumer from the cached instances and from the cache itself.

In Example 2 we decided to provide two implementations of the service, one for run time and one for test purposes.

// Classic compostion of consumer and service

public class Consumer {
    private IDataService _service;

    public Consumer() {
        if (App.IsTestMode) {
            _service = new TestDataService();
        }
        else {
            _service = new DataService();
        }
    }
}

public interface IDataService {
    Task<DataItem> GetData();
}

public class DataService : IDataService {
    public async Task<DataItem> GetData() {
        // TODO: Provide a runtime implementation of the GetData method.
    }
}

public class TestDataService : IDataService {
    public async Task<DataItem> GetData () {
        // TODO: Provide a test implementation of the GetData method.
    }
}

Consumer with dependecy injection, the code becomes much cleaner, as shown in Example 3.

// Dependecy Injection

public class ConsumerWithInjection {
    private IDataService _service;

    public ConsumerWithInjection(IDataService service) {
        _service = service;
    }
}

Then we need to take of creating the service outside of the Consumer and injecting it, this is where the IoC container becomes useful.

MVVM Light's SimpleIoC

SimpleIoC is, as the name indicates, a simple IoC container, which allows registering and getting instances from the cache in an uncomplicated manner.

It also allows composing objects with dependency injection in the constructor.

With SimpleIoC, we can register the IDataService, the implementing class or classes and the Consumer class, as shown in Example 4.

// Registering the IDataService and the Consumer

if (App.IsTestMode) {
    SimpleIoc.Default.Register<IDataService, TestDataService>();
}
else {
    SimpleIoc.Default.Register<IDataService, DataService>();
}

SimpleIoc.Default.Register<ConsumerWithInjection>();

Basically what we do in Example 4 is the following: if the application is in the test mode, every time anyone needs an IDataService, pass the cached instace of TestDataService; otherwise, use the cached instance of DataService.

Note: the action of registering does not create any instance yet - the instatiation is on demand, and only executed when the objects are actually needed.

Next we create the ConsumerWithInjection instance as shown in Example 5]].

// Getting the ConsumerWithInjection Instance

public ConsumerWithInjection ConsumerInstance {
    get {
        return SimpleIoc.Default.GetInstance<ConsumerWithInjection>();
    }
}

When the getter in Example 5 is called, the SimpleIoc container will run the following steps:

  1. Check whether the instance of ConsumerWithInjection is already existing in the cache. If yes, the instance is returned.
  2. If the instance doesn't exist yet, inspect the ConsumerWithInjection's constructor. It requires the instance of IDataService.
  3. Check whether an instance of IDataService is already available in the cache. If yes, pass it to the ConsumerWithInjection's constructor.
  4. If not, create an instance of IDataService, cache it and pass it to the ConsumerWithInjection's constructor.

    It is not strictly necessary to use the constructor injection shown earlier in Example 3, although it is an elegant manner in which to compose objects and to decouple the dependencies between objects.

Keyed instances

The GetInstance method can also return keyed instances. This means that IoC container can create multiple instances of the same class, keeping them indexed with a key.

When GetInstance is called with a key, the IoC container checks whether an instace of that class is already saved with that key. If it is not, the instace is created before it is returned. It is then saved in the cache for later reuse.

It is also opssible to get all the instances of a given class, as shown in Example 6.

// Getting Keyed instances, and getting all the instances

// Default instance
var defaultInstance = SimpleIoc.Default.GetInstance<ConsumerWithInjection>();
// Keyed instances
var keyed1 = SimpleIoc.Default.GetInstance<ConsumerWithInjection>("key1");
var keyed2 = SimpleIoc.Default.GetInstance<ConsumerWithInjection>("key2");
var keyed3 = SimpleIoc.Default.GetInstance<ConsumerWithInjection>("key3");
// Get all the instances
var allInstances = SimpleIoc.Default.GeAllInstances<ConsumerWithInjection>();

Various ways to register a class

Each IoC container has certain features that make it unique in the way that classes are registered. Some of the use code-only configuration, while others can read external XML files, allowing for great flexibility in the way that classes are instatiated by the container. Others allow for powerful factories to be used.

Some, like MVVM Light's SimpleIoc, are more simple and straightforward.

Registration can occur in a central location (often called the Service Locator ), where important decisions can be taken, such as when to use the test implementation for all the services.

In some MVVM applications, a class named ViewModelLocator is used to create and expose some of the application's ViewModel s. This is a convient location to register most of the services and service consumers. In fact, some ViewModel s can also be registered with the IoC container.

In most cases, only the ViewModel s that are long-lived are registered in the ViewModelLocator class. Others may be created ad hoc. In navigation apps, these instances may be passed when the navigation occurs. In some cases, SimpleIoc may be used as a cache for keyed instances in order to make this step easier.

To make the IoC container easier to swap with another, many such containers use the Common Service Locator implementation. This relies on a common interface ( IServiceLocator ) and the ServiceLocator class, which is used to abstract the IoC container's implementation.

Because SimpleIoc implements IServiceLocator, we have the code shown in Example 7 execute in the same manner as the code in Example 6.

// Registering the ServiceLocator

ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

// Default instance
var defaultInstace = ServiceLocator.Current.GetInstance<ConsumerWithInjection>();
// Keyed instances
var keyed1 = ServiceLocator.Current.GetInstance<ConsumerWithInjection>("key1");
var keyed2 = ServiceLocator.Current.GetInstance<ConsumerWithInjection>("key2");
var keyed3 = ServiceLocator.Current.GetInstance<ConsumerWithInjection>("key3");
// Get all instances
var allInstances = ServiceLocator.Current.GetAllInstances<ConsumerWithInjection>();

Instead of registering a class and delegating the instance creation to the IoC container, it is also possible to register a factory expression. This delegate returns an instance, and is often expressed using a lambda expression.

public async void InitiateRegistriation() {
    // Registering at 0:00:00
    SimpleIoc.Default.Register(() => new DataItem(DateTime.Now()));
    await Task.Delay(5000);
    // Getting at 0:00:05
    var item = ServiceLocator.Current.GetInstance<DataItem>();
    away Task.Delay(5000);
    // Getting at 0:00:10. Creation time is still the same
    item = ServiceLocator.Current.GetInstance<DataItem>();
}

MVVM Light's ViewModelLocator

View Services

Servies are classes that provide the ViewModel s with data and functionality. Sometimes, however, the ViewModel also needs another kind of service in order to use functionality in the View. In this case, we talk about View Services.

Two typical View Services are the NavigationService and the DialogService.

Each Page performs navigation by using a built-in NavigationService property. Since a ViewModel is a plain object it does not have such a built-in property, and here the IoC container comes in handy: the NavigationService is registered in the ViewModelLocator, cached in the IoC container and can be injected into each ViewModel as needed. This operation is shown in Example 10.

public class ViewModelLocator {
    static ViewModelLocator() {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic) {
            SimpleIoc.Default.Register<IRssService, Design.DesignRssService>();
        }
        else {
            SimpleIoc.Default.Register<IRssService, RssService>();
        }

        SimpleIoc.Default.Register<INavigationService, NavigationService>();
        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main {
        get {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }
}

public class MainViewModel : ViewModelBase {
    private readonly IRssService _rssService;
    private readonly INavigationService _navigationService;

    public ObservableCollection<RssItem> Items {
        get;
        private set;
    }

    public MainViewModel(IRssService rssService, INavigationService navigationService) {
        _rssService = rssService;
        _navigationService = navigationService;

        Items = new ObservableCollection<RssItem>();
    }
}