Click here to Skip to main content
13,146,742 members (80,349 online)
Click here to Skip to main content
Add your own
alternative version

Stats

41.6K views
54 bookmarked
Posted 15 Sep 2014

Introducing Calcium for Xamarin.Forms

, 15 Sep 2014
Rate this:
Please Sign up or sign in to vote.
Create best-in-breed cross-platform MVVM apps using Calcium for Xamarin.Forms.

Calcium for Xamarin.Forms Phones

Series Introduction

Xamarin.Forms is Xamarin’s new cross-platform UI framework that allows you to build user interfaces for iOS, Android and Windows Phone using XAML.

In this series you learn how to do things with Xamarin Forms that you’ll not find anywhere else. For example, you see how to create a cross-platform Application Bar component using the Xamarin Forms native rendering API with Menu Item support that works on iOS, Android, and Windows Phone; and which offers more features than the built-in Windows Phone Application Bar.

You learn how it is possible to place images anywhere in a shared project as Content resources like in Windows Phone, and consume them in the same way across all three platforms.

You learn how to use T4 templates to enable localizability for your Android app. You also see how to create static bindings to your .resx files using T4 generated designer classes; allowing you to localize your app in the same manner for all three platforms.

You see how to extend beyond current Xamarin Forms API capabilities to implement a quasi-data-template selector to materialize viewmodels in an MVVM compatible way.

You learn how to assemble your Visual Studio projects to decrease friction when you are sharing code using the new Shared Project type.

In addition, in this series of articles you are guided through the basics of developing apps using Xamarin.Forms. You learn how to use the Calcium MVVM framework to build multifaceted cross-platform apps with Xamarin Forms.

If you already have some experience with Xamarin Forms, then this article may be right up your alley. If you are experienced with XAML for UI development; for WPF, Silverlight, or WinRT, and have an understanding of MVVM, Inversion of Control (IoC) and Dependency Injection (DI); then I’d say this article is certainly worth a read.

  • Part 1. Introducing Calcium for Xamarin Forms (this article)
  • Part 2. Using MVVM to create Tabbed Interfaces with Calcium for Xamarin Forms
  • Part 3. Building Localizable Cross-Platform Apps with Calcium for Xamarin Forms
  • Part 4. Creating a Cross-Platform Application Bar with Calcium for Xamarin Forms
  • Part 5. Using Calcium for Xamarin Forms to Resolve Images in a Shared Asset Project
  • Part 6. Creating a User Options Page with Calcium for Windows Phone

In this Article

In this article you learn about the origins of Calcium and at some of its key features. You see how to install the Calcium NuGet packages. You look at creating a Xamarin Forms shared project, and at initializing your app with a Bootstrapper. You see how to create a basic page in XAML and how to bind that page to a viewmodel. Finally, you see an overview of some of Calcium’s default services, including a Dialog Service, Settings Service, and User Options Service.

Background

Xamarin.Android and Xamarin.iOS are two rather distinct tools for creating apps for either platform. Each has its own disparate set of APIs for creating user interfaces, mirroring those of the underlying platform. As far as cross-platform development goes, I doubt it was ever Xamarin’s focus for these two technologies to be used as a means to create cross-platform apps. The intention, in my view, was to allow developers to leverage their C# skills to develop for iOS or Android; not both.

I had been hoping, as I’m sure were many other developers, that Xamarin would take up the mantle and provide a unified UI layer for both platforms. And now of course Xamarin has done just that. In addition, with the Xamarin and Microsoft partnership, we see Windows Phone included in the mix of supported platforms.

As you see in this series of articles, Xamarin has come a long way in providing a unified UI layer, however there are disparities between iOS, Android, and Windows Phone that can cause friction when developing cross-platform apps. These include localizability differences, differences in resolving resources and images, and managing assembly XML namespaces in XAML. Yet, despite these differences, in my view Xamarin Forms provides the best tooling for creating native cross-platform mobile apps. In this series of articles you see ways to overcome some of the existing pain points, such as sharing images between projects without sacrificing structure and avoiding the single image directory requirement for iOS and Android. 

What is Calcium?

Calcium started life as one of those MVVM frameworks and an extension of Prism, formally Composite Application Library. Times have changed and Calcium has since mostly ditched its Prism attachment (apart from the desktop version), and much of what was leveraged in Prism has been re-implemented within Calcium itself (or dropped as not all that productive). Calcium began life as a WPF MVVM framework but has gone on to embrace mobility, in particular Windows Phone and now Xamarin Forms.

Calcium enabled me to build Intellicam for Windows Phone in just two days, and is the backbone of Surfy which is arguably the best third party web browser for Windows Phone.

Calcium has grown and evolved substantially over time. So much so that sometimes I forget just how much juicy goodness is in there. In fact, it’s only writing an article like this one that I am reminded of the value that has been built up over the last few years. Yep, it’s big, and quite mature; I started developing Calcium in 2009. But it has been periodically kneaded and augmented over the years and is used in quite a few commercial applications.

Over the years of developing MVVM applications, I’ve incorporated those things into Calcium that I have felt to be inherently useful. I began writing Calcium as a framework. As with so many other well intentioned frameworks out there, in the beginning it was a case of: presumed value first, real world value second. But then, with time, this changed, and the best ideas from the applications I was building gradually made their way into Calcium; after the fact. Calcium is used in commercial products and has been developed to address common challengers faced within production apps. Calcium, however, is not burdened by domain specific code.

Calcium is not just an MVVM framework. It includes a cavalcade of components that combine together to solve all those common app development challengers you face day to day. Calcium contains pretty much all the key features you’d expect from a mature MVVM framework. But in many places I believe it offers characteristics over and above frameworks that you are probably more familiar with. Here are just a few examples:

Enhanced Commanding Support

The Calcium ICommand implementation uses parameter type value coercion. Enum types, for example, can be used as command parameters in XAML, and they are converted to the correct type for you by the time they hit your viewmodel. That means you can leverage Generic ICommands in XAML and you don’t need to make assumptions or perform type conversion of parameter values. This work was inspired by Pete Blois terrific work on implicit type coercion.

UICommands offer Visibility, Text and Icon properties that can be changed according to the logic that can be encapsulated by the command logic. They also work in unison with a number of controls, including Calcium’s AppBar for Xamarin Forms, and Calcium’s User Options system. You see examples of these features in a number of the upcoming articles.

Frictionless INotifyPropertyChanged (INPC) Infrastructure<o:p>

Calcium’s INPC system has automatic UI thread affinity. Modifying a property in a viewmodel (an ObservableObject) from a non-UI thread automatically raises a property changed event on the UI thread if necessary. In addition, the PropertyChangeNotifier can be applied to any class and makes use of weak referencing to prevent memory leaks. In addition, a PropertyChanging event is raised before the PropertyChanged event to give other components a chance to cancel the change.

Settings Service

Calcium’s setting service allows you to save settings on whatever platform your app is running. It includes notifications that allow you to cancel setting changes, and to be notified before a setting change takes place. It also provides the means to serialize values, composite objects, or even to customize the serialization of objects via an IXmlConvertible interface.

Options System

Calcium’s options system enables you to quickly create a user options page for your app. Categorized options can be added with a single line of code. Templates control how types of options are displayed. The options system works in unison with the settings service to automatically write changes back to persistent storage.

Inversion of Control and Dependency Injection

Calcium includes a built-in IoC container supporting Dependency Injection; attribute based constructor and property injection, and which is also interchangeable. If Calcium’s IoC container or Microsoft Unity don’t fit the bill, you can create adapters for whatever implementation you’d like to use.

Cross-Platform Dialog Service<o:p>

Calcium’s DialogService has an asynchronous API, implemented for each platform with an extensibility model that allows you to present dialogs to the user and easily receive user feedback. 

Extensible String Parser<o:p>

Calcium includes an extensible String Parser service for which you can create recognizable tags that are processed at run-time to insert information in to a string. This offers the ability to create dynamic localizable strings.

An Undo Redo Stack for your App

Calcium includes an undo redo task system, which gives the user of your app the ability to undo an action, or redo that action.

Weak Referencing Messaging System<o:p>

The weak referencing messaging system, known as the Messenger, uses a declarative interface based approach that allows an object to be notified of an event from another component within the app. A set of standard message classes are included that allow you to send payload objects to listeners, or to even cancel a message.

Collections, such as an ObservableList <o:p>

Calcium includes collections such as the ObservableList that allow you to postpone collection changed events to perform bulk updates, without causing multiple updates to UI controls and slowing the UI thread.

Input Validation System<o:p>

Calcium includes an attribute based asynchronous input validation system that allows you to easily validate forms. I have not yet created the UI for visualising validation error in Xamarin Forms.

ViewModel State Persistence System<o:p>

Calcium allows you to maintain the state of your application across tombstoning (Windows Phone) using an attribute based system or a programmatic property registration system. I have not yet wired this up for Xamarin Forms.

Most of this infrastructure can now be leveraged on Windows, Windows Phone, and thanks to Xamarin iOS and Android. This series of articles covers what is in Calcium and is a preview of what is inevitability coming to Calcium for Xamarin Forms. 

<o:p>

Requirements

These articles are written from the perspective of having both a Xamarin iOS and Android Business installation. If you have one, but not the other, then you may disregard those sections that do not apply to your license. If you have an Indie license, then the Visual Studio specific guidance won’t apply to you. Though, you can still leverage the Calcium codebase.

The Xamarin tooling works well on Windows. The fact is, however, that if you are looking to build iOS apps, you need to know your way around OSX. In fact, a Mac is a requirement for building your iOS apps. I used Linux quite a bit in my undergraduate years and my early days as a Java programmer, so for me last year, having a new Mac Book on my desk felt familiar and fun. If you’re looking to get into iOS development, I hope you have a similar experience.

Source Code for Calcium and Example Apps<o:p>

The source code for Calcium for Xamarin.Forms and the examples is located at https://calcium.codeplex.com/SourceControl/latest

There are various solutions throughout the repository. The one you are interested in is located in the \Trunk\Source\Calcium\Xamarin\Installation directory, and is named CalciumTemplates.Xamarin.sln.

The structure of the CalciumTemplates.Xamarin solution is shown in Figure 1. You can see the example 'template' projects have been highlighted. These are the projects that contain much of the example source code that is presented within this article series.

Solution Structure

Figure 1. Structure of CalciumTemplates.Xamarin Solution

Before we look at using Calcium in conjunction with Xamarin Forms, let’s begin with a brief getting started guide.

Getting Started with Xamarin Forms

Let’s begin by creating a new Xamarin mobile shared app. You can choose the portable library approach if you wish, but for this series of articles I’ll be using the shared project type. Figure 2 shows the Visual Studio New Project dialog with the Shared Asset project type selected.

Creating a new shared project.

Figure 2. Creating a new Xamarin Forms project.

If you have both Xamarin.iOS and Xamarin.Android installed, selecting a Xamarin Mobile Shared App creates four projects; one for each platform: Windows Phone, iOS, and Android, and a Shared project that automatically links all file in the shared project to the platform specific projects. I recommend against placing platform specific code into a launchable platform specific project. I realize that sounds odd. I say it because mobile OS updates can occur frequently and you may find yourself trying to support two or more versions of an SDK within a single platform specific project. I faced this recently with Windows Phone 8.1. Linking files is a nuisance, that’s why the new Shared project type is boon for this type of work.

When developing your cross-platform app in Visual Studio, you have the choice to spend your time debugging against your iOS project, your Android project (depending on your licensing), or your Windows Phone project. The Visual Studio tooling for Windows Phone is superior to both the Android and iOS tooling. This is to be expected, Microsoft has invested heavily in Windows Phone development tooling. Debugging has a far shorter deployment and launch time when using the Windows Phone emulator. So, if you’re considering ditching the Windows Phone project for whatever reason and focussing your energy on another platform, I recommend against it; if only for reasons of productivity. 

Avoiding XML Namespace Mayhem

When setting up XML namespaces in XAML files it’s important to be mindful of your assembly names. If you’re looking to target a class library across multiple platforms, then the XML namespace definitions in your XAML files must include the name of the assembly. In this case, XAML files must include an assembly part within xmlns definitions, so it’s important to use the same assembly name for your platform specific projects if you intend to reuse custom controls. This is the biggest downside of using Shared projects over portable class library projects. When your types are located in a Portable library, you don’t need to worry about namespaces discrepancies across projects; with Shared projects you do. Despite this, I still prefer the flexibility of the Shared project type.

TIP. I generally like to unify assembly and namespaces across platforms because I’ve found this makes sharing code simpler.

When changing the default namespace in a newly generated Windows Phone project, you’ll receive build errors related to the generated LocalizedResources class. In an upcoming article you see how to implement localizability in your app, which is compatible across all three platforms. You’ll not need the LocalizedResources.cs file.

Unifying the namespaces is also an important step if you are looking to share localized resources in resx files. You see how to share localized resources in a later section.

NOTE. While Xamarin Forms includes a set of useful built-in mechanism that allow you target and exclude particular platforms, none exist for changing XML namespace definitions in XAML files. Xamarin Forms apps don’t offer a way to programmatically map CLR namespaces with XML namespace definitions, such as with the XmlnsDefinitionAttribute, like you would in a WPF or Silverlight app. It would otherwise be a piece of cake to conditionally add XmlnsDefinition attributes to your assembly using compilation symbols. I’m hoping that we’ll see more from Xamarin to address this in the future.

Related to this missing XML namespace mapping capability is the lack of intellisense in Xamarin Forms. I find that one of the challengers with writing Xamarin Forms apps at the moment is the lack of intellisense in the Visual Studio XAML editor. 

Installing the Calcium NuGet Packages

When I began work on Calcium, back in the day, NuGet didn’t exist. I spent an inordinate amount of time crafting custom Visual Studio installers. Only to watch them break with each new version of Visual Studio. So, to reduce my own rate of mental decline I’m now using NuGet to distribute Calcium.

To install Calcium, right click on your newly minted Xamarin solution and select “Manage NuGet Packages for Solution…”

Figure 3 shows the Manage NuGet Packages dialog. Select the item “Calcium for Xamarin Forms (All Platforms).” If you are only targeting a specific platform then you may want to be more specific about the package you select.

You may notice that I am using a “LocalFeed” feed for the NuGet packages. By the time you read this, the packages will be available on nuget.org. Also, depending on when you read this, you may also need to select “Include Prerelease” from the drop down list.

Manage NuGet Packages for the Solution

Figure 3. Selecting “Manage NuGet Packages for Solution”

Note that these packages are assembly only packages. No other artefacts are placed within your project. That means you can add and remove the packages without fear of having your project content being messed with. I can’t say the same for the dependent packages though. I rather dislike packages that choose to install icons and whatnot. I’m looking at you Windows Phone Toolkit. ;)

Figure 4 shows the 'Manage NuGet Packages' dialog that is used to select the Calcium packages.

Select Calcium from the NuGet Manager

Figure 4. Select Xamarin Forms (All Platforms)

The default Xamarin template starts you off with a shared App class. This class has a single method named GetMainPage, as shown in Listing 1. The GetMainPage method is the common entry point for the Xamarin.Forms part of your app, and is used by the iOS, Android, and Windows Phone projects respectively.

Listing 1. App.GetMainPage method

public class App
{
       public static Page GetMainPage()
       {
              return new ContentPage
              {
                     Content = new Label {
                           Text = "Hello, Forms !",
                           VerticalOptions = LayoutOptions.CenterAndExpand,
                           HorizontalOptions = LayoutOptions.CenterAndExpand,
                     },
              };
       }
}

Xamarin Forms adapts the Xamarin Page instance returned from the GetMainPage method to a platform specific type. See Listing 2.

As an aside, I was surprised to see how this is achieved under-the-covers. For the Windows Phone platform, for example, a Xamarin Platform instance is cast to a UIElement using an implicit operator. I am a little puzzled why this approach was taken. I assume it is for convenience, to allow the ‘platform’ code to be rolled into the native UIElement, while allowing the Xamarin Forms IPlatform implementation to be kept internal. But, at the time of writing, IPlatform is public in the Windows Phone library. 

Listing 2. Forms.ConvertPageToUIElement method

public static UIElement ConvertPageToUIElement(this Page page, PhoneApplicationPage applicationPage)
{
    Platform platform = new Platform(applicationPage);
    platform.SetPage(page);
    return (UIElement) platform;
}

Besides curiosity, my first reason for firing up Reflector and digging snooping around the Xamarin Forms code was to find a way to get my hands on the Xamarin Forms Platform object. You see, my approach to navigation in Calcium has hitherto depended upon having an object (e.g. a Frame) that could perform page navigation independently of the Page model. As it turns out, you are able to retrieve an instance of the IPlatform object when running on Windows Phone, in which there is an INavigation object. This was, however, not the case for Android. When I discovered this, I soon realized that the differing ‘native’ navigation models of the platforms meant that handling navigation globally would not be easily achievable. So, I changed tack. Rather than registering a lambda to retrieve an INavigation object from the IoC container, I had to resort to wiring up the INavigation object of a Xamarin Forms VisualElement to each viewmodel when the VisualElement (Page) is created. It’s not what I had hoped, but it works.

Calcium’s ViewBinderExtensions class’s BindToInfrastructure method takes a VisualElement and uses the IViewBinder implementation to bind the ViewModel’s Navigation property to the page’s Navigation property. See Listing 3.

Listing 3. ViewBinderExtensions Class

public static class ViewBinderExtensions
{
       public static void BindToInfrastructure(this VisualElement visualElement)
       {
              var viewBinder = Dependency.Resolve<IViewBinder, ViewBinder>();
              viewBinder.BindToInfrastructure(visualElement);
       }
}

Underpinning the BindToInfrastructure method is an IViewBinder object. The BindToInfrastructure extension method uses an instance of the ViewBinder class to set the view’s Navigation property to the ViewModel’s Navigation property using reflection. See Listing 4. If the VisualElement’s Navigation property is not null and the object that is data bound to the VisualElement has a Navigation property of type INavigation, then the property is set.

Attaching the INavigation object to a viewmodel could also be achieved through data binding; binding the Navigation property to the viewmodel. But, I chose against that approach because it felt overcomplicated and it’s far harder to diagnose binding failure errors than it is to step through a method.

Also within the BindToInfrastructure method we bind the page’s IsBusy and Title properties to the corresponding properties in Calcium’s ViewModelBase class. As serendipity would have it, I didn’t have modify Calcium to support this, as these properties were already present in Calcium’s ViewModelBase class.

If you’d like to do things differently than the default ViewBinder class, you can register your own IViewBinder object with the Dependency system.

NOTE. If you attempting to call BindToInfrastructure for many VisualElements at once, you may want to consider caching the PropertyInfo value for improved performance. Let me know if you are.

Listing 4. ViewBinder.BindToInfrastructure Method

public void BindToInfrastructure(VisualElement visualElement)
{
       var viewModel = visualElement.BindingContext;

       if (viewModel != null && visualElement.Navigation != null)
       {
              INavigation navigation = visualElement.Navigation;

              if (navigation != null)
              {
                     Type viewModelType = viewModel.GetType();

                     PropertyInfo propertyInfo = viewModelType.GetProperty(
                          "Navigation", typeof(INavigation));

                     if (propertyInfo != null)
                     {
                           propertyInfo.SetValue(viewModel, navigation);
                     }

                     Dependency.Register<INavigation>(navigation);
              }
       }

       if (visualElement is Page)
       {
              visualElement.SetBinding(Page.IsBusyProperty, new Binding("Busy"));
              visualElement.SetBinding(Page.TitleProperty, new Binding("Title"));
       }
}

Constructing a XAML Page in Xamarin Forms

As it happens, I’m not keen on building interfaces in code. One of the key reasons I like Xamarin Forms, is that it allows me to mark-up my UI declaratively using XAML. On this note, let’s create a landing page in XAML. You do this by creating a new ContentPage, which is shown as “Forms Xaml Page” in Visual Studio’s Add New Item dialog. This produces a new XAML page, which resembles a XAML page that you’d see in a WPF, Silverlight or a WinRT project. See Listing 5.

The default template contains a ContentPage root element and a Label that is data bound to the MainText property of the page’s binding context.

Listing 5. A newly created Xamarin Forms ContentPage

<?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="CalciumSampleApp.Views.MainView">
       <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Binding in Xamarin Forms

If you’re not already familiar with data-binding in XAML, data-binding works by assigning a binding-context, which can be any object, to a visual element (a BindableObject). You can then use binding expressions within your XAML to get and set property values of the binding-context. In addition, a binding-context also allows elements to inherit a binding-context from a parent element.

NOTE: In Xamarin.Forms the BindingContext property of BindableObject is analogues to the FrameworkElement’s DataContext property in WPF or Silverlight.

Understanding the Xamarin Forms Page Class Hierarchy

The ContentPage is generally the first choice for defining a page in your app. In addition, NavigationPage can be used to indicate to Xamarin Forms that the page participates in navigation, and that a navigation bar should be rendered for iOS and Android. Windows Phone dispenses with onscreen navigation, and instead relies solely on the hardware back button for navigation.

A Xamarin Forms CarouselPage allows you to display zero or more child pages and swipe between them, like a gallery. A TabbedPage does this too, but a TabbedPage also provides the user with a navigation control to move between the pages. In Windows Phone a TabbedPage is rendered as a Pivot, while a CarouselPage is rendered as a Panorama. You look at the TabbedPage in greater detail in Part 2: Using MVVM to create Tabbed Interfaces with Calcium for Xamarin Forms, and at using Calcium to bind the TabbedPage to a collection of viewmodels, representing each viewmodel with a different view, which is not something that is supported in Xamarin Forms out-of-the-box.

The Xamarin Forms API makes it easy to turn any page into a NavigationPage by simply wrapping your page in a NavigationPage instance. This is achieved like so:

ContentPage page = new MyPage();

NavigationPage navigationPage = new NavigationPage(page);

Objects that are present in the Xamarin Forms visual tree derive from BindableObject. This holds true for pages. See Figure 4.

Page Class Hierarchy

Figure 4. Page Class Hierarchy

With a view defined in XAML we can return to the App class in the shared project. Rather than building up the page in code, we are now able to create and return an instance of the MainView page. See Listing 6.

Calcium’s Dependency class is used to resolve the instance of the MainView class. We use inversion of control here so that the view and is automatically populated with whatever services it requires, and we rely on dependency injection (DI) to pass an instance of the MainViewModel to the view’s constructor.

Listing 6. The new App.GetMainPage method.

public class App
{
       public static Page GetMainPage()
       {
              var bootstrapper = new Bootstrapper();
              bootstrapper.Run();

              MainView result = Dependency.Resolve<MainView>();

              return new NavigationPage(result);
       }
}

The code-beside file for the MainView page contains two constructors: a parameterless constructor and one requiring an instance of a MainViewModel.  The Calcium DI engine selects which constructor to use based on the following criteria:

  1. If the constructor is decorated with an InjectDependencies attribute it gets first preference.
  2. Otherwise the public constructor with the greatest number of arguments is selected.
  3. If no public constructor exists, the SimpleContainer attempts to use an internal constructor.

NOTE. In Windows Phone, due to security restrictions, instantiating a type with an internal constructor is prohibited (failing with a SecurityException) if the type is in a different assembly than the calling code. I tend to favor internal visibility over public for types wherever possible. The reason is that most obfuscators I’ve used do a better more reliable job of safely hiding away the names of types when they are internal.

You’ll notice I leave a default parameterless constructor in place with the expectation that at some point Xamarin will release a designer surface for XAML files that will probably require a parameterless constructor.

Examining the MainView constructor, you see a call to InitializeComponent (see Listing 7). This is an automatically generated method, present in a file named according to your XAML file e.g. MainView.xaml.g.cs, which must be called by user code. The ‘g’ in the filename stand for generated. Its purpose is to retrieve and load the XAML from the assembly.

The BindingContext of the page is set to the view mode. The BindToInfrastructure extension method, which you saw earlier, is used to pass the INavigation object to the viewmodel and to attach some default bindings between the view and the viewmodel.

Listing 7. MainView constructor is injected with an instance of MainViewModel

public MainView(MainViewModel viewModel)
{                
    InitializeComponent();

    BindingContext = viewModel;

    this.BindToInfrastructure();

    Appearing += HandleAppearing;
}

The Appearing event of the Page class can be used to perform an activity that should occur after the page has been instantiated, but before it is materialized in the user interface. Conversely, there is a Disappearing event which occurs when the page is going out of view. These events are analogous to the VisibilityChanged or Loaded events present in WPF and Silverlight.

NOTE. The Appearing and Disappearing events may occur more than once. For example, the Appearing event occurs when you navigate back to a page that was previously shown in the UI. Also be aware of the order in which these events occur. The Disappearing event occurs in the current page, after the Appearing event occurs in a page that is being navigated to.

Using a Bootstrapper to Initialize Your App

In the sample app you see that I’ve replaced the content of the GetMainPage method with the content of listing 6. Before the main page is resolved the Bootstrapper class's Run method is called.

The Bootstrapper class offers a centralized way of managing the startup process of your app. In Calcium the Bootstrapper is used to initialize the IoC container, registering the default type mappings that are used by the IoC and DI system, and to perform any other start-up related tasks. You look more closely at this process in a moment.

Once the Bootstrapper has completed running, the MainView is resolved using the static Resolve method of Calcium’s Dependency class.

In this section we briefly look over the activities of the Bootstrapper and you see an overview of the types that are registered with Calcium’s IoC container.

Xamarin.Forms comes with its own IoC container, and you may be wondering why use Calcium’s instead? Well, you’re free to use Xamarin’s if you wish. Calcium’s lets you replace the underlying IoC container. Internally, Calcium’s default DI and IoC system uses a class named SimpleContainer, which implements Calcium’s IContainer interface. So you are free to implement adapters for whatever IoC container you’d like to use. Calcium includes one for Unity, and of course the default container. I’ve found the default container to be more than adequate.

In Listing 6, you saw that the MainView object is resolved without an explicit type registration ever having been made. Because the type argument is a concrete type, if the IoC container can’t resolve a registered type, then it instantiates an instance, and automatically resolves any dependencies required by it.

A key responsibility of the Bootstrapper class is to initialize the IoC container. You register an IContainer with the IoC and DI system using the InitializeContainer extension method, as shown:

SimpleContainer container = new SimpleContainer();

container.InitializeContainer();

Behind the scenes this initializes the Microsoft.Practices.ServiceLocation.ServiceLocator with the SimpleContainer instance, and extends it to provide some other service registration capabilities that are notably absent from the Microsoft ServiceLocator APIs.

An Overview of the Services Registered within the Bootstrapper

Once the container is registered, the Bootstrapper registers a number of default services, which we now briefly examine.

Settings Service

Calcium abstracts the way application settings are stored for each platform. It does this by initializing the Calcium SettingsService with a platform specific instance of the SettingsStore class. See the following excerpt:

SettingsStore settingsStore = new SettingsStore();
SettingsService settingsService = new SettingsService(settingsStore);

The SettingsStore for Windows Phone uses the IsolatedStorageSettings API. Android uses the ISharedPreferences API, and iOS uses a custom IsolatedStorageSettings API in conjunction with the Silverlight Serializer; which, by the way, makes serializing just about anything a piece of cake. The ISettingsStore interface is shown in Listing 8.

Listing 8. ISettingsStore interface.

public interface ISettingsStore
{
       bool TryGetValue(string key, out object value);

       bool Contains(string key);

       bool Remove(string key);

       Task Clear();

       Task Save();

       object this[string key] { get; set; }
}

The SettingsService class calls through to the ISettingStore implementation, and provides some serialization capabilities and object type coercion over and above the ISettingsStore implementation. In addition the SettingsServices provides a setting change event and a cancellable setting changing event. Change notifications can be received using either a regular CLR event or using Calcium’s weak referencing messaging system. You see more on this topic later.

Dialog Service

Next up to be registered within the Bootstrapper is the DialogService. DialogService is an asynchronous user messaging system that allows you to display message dialogs and toasts to your users and to ask users question, using an abstracted API. Once again, there’s a specific implementation for each platform.

For example, to ask the user a simple yes no question, you could do something like the following:

bool response = await DialogService.AskYesNoQuestionAsync(
                           "Allow app to run under the lock screen?",
                           "Lock Screen");

One of the nice things about the DialogService is that it can be extended to cover new platforms or modified with new behaviour, simply by overriding two methods in the DialogServiceBase class. For a particular scenario I even created a command line version of the DialogService.

When the DialogService is initialized in the Bootstrapper, you can provide default dialog captions if you wish, as shown:

var dialogService = new DialogService
       {
           /* Lambda expressions are used to retrieve the default message service captions,
            * which allows the language to be changed at run-time. */
           DefaultMessageCaptionFunc = () => AppResources.DialogService_DefaultMessageCaption,
       };

Dependency.Register<IDialogService>(dialogService);

The DialogService allows you to override the default captions with localized strings. Disregard this localization aspect for now. There is a large section describing cross-platform localizability coming up in Part 3: Building Localizable Cross-Platform App with Calcium for Xamarin Forms.

The UI Synchronization Context

Several components within Calcium rely on being able to post and send actions to the UI thread. Calcium makes use of platform specific implementations of a UIContextProvider, which is able to retrieve a synchronization context for each of the platforms. It’s registered in the Bootstrapper as shown:

Dependency.Register<IProvider<ISynchronizationContext>, UIContextProvider>();

To invoke an action on the UI thread you can always do this:

var context = Dependency.Resolve<IProvider<ISynchronizationContext>>().ProvidedItem;
context.InvokeWithoutBlocking(() => { DoSomethingOnTheUIThread(); });

Sending Messages to Weakly Referenced Listeners

Like some other MVVM frameworks, Calcium has a weak referencing messaging system. In Calcium, the Messenger class uses a declarative interface based approach to subscribing to notifications. If an object wishes to be notified of an event, it implements the IMessageSubscriber<T> interface. Where T indicates the type of message. For example, the ViewModel class, which is the customizable base viewmodel for your app, implements IMessageSubscriber<ApplicationLifeCycleMessage>

When your app is launched, deactivated, exited and so forth, any subscriber within your app is notified. Please not that while there’s a Windows Phone implementation, I’m yet to implement the ApplicationLifeCycleMessage event in iOS and Android.

Incorporating a User Options Page

One of the most common tasks that you face when building any app, is the creation of an options page. This is an area where Calcium really shines. You see, Calcium has an abstracted options system that allows you to define an option in a single line of code. The option is then automatically displayed on an options view in your app, and when the user modifies the option, the options sub-system takes care of persisting the change.

The options system is designed with localization in mind. If you wish to see a real-world example of the Calcium’s options system at work, check out the options screen in Surfy for Windows Phone.

To create an option is as simple as writing the following:

new BooleanUserOption(() => "Example Title", "A key for the settings service", () => aDefaultValue)

You then add the option to a group of options and submit them to the IUserOptionsService. Calcium takes care of the rest. Calcium will retrieve and save values to the settings service automatically.

You look at the User Options system in greater detail in Part 6: Creating a User Options Page with Calcium for Windows Phone.

The Bootstrapper defines a number of other services such as an IMarketplaceService, which allows you to jump to the platform specific ratings page for your app, or to buy your app.

Conclusion

In this article you learned about the origins of Calcium and took a peak at some of its key features. You saw how to install the Calcium NuGet packages. You looked at creating a Xamarin Forms shared project, and at initializing your app with a Bootstrapper. You saw how create a basic page in XAML and how to bind that page to a viewmodel. Finally, you saw an overview of some of Calcium’s default services, including a Dialog Service, Settings Service, and a User Options Service. In subsequent articles you delve deeper into Calcium’s core services.

In the next article you see how to create a tabbed or carousel page that is populated purely via data-binding and a custom templating system.

I hope you find this project useful. If so, then I'd appreciate it if you would rate it and/or leave feedback below. This will help me to make my next article better.

<o:p>

History

September 2014

  • Initial publication.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Daniel Vaughan
President Outcoder
Switzerland Switzerland
Daniel Vaughan is a eight-time Microsoft MVP and co-founder of Outcoder, a Swiss software and consulting company dedicated to creating best-of-breed user experiences and leading-edge back-end solutions, using the Microsoft stack of technologies--in particular Xamarin, WPF, and the UWP.

Daniel is the author of Windows Phone 8 Unleashed and Windows Phone 7.5 Unleashed, both published by SAMS.

Daniel is the developer behind several acclaimed mobile apps including Surfy Browser for Android and Windows Phone. Daniel is the creator of a number of popular open-source projects, most notably Codon.

Would you like Daniel to bring value to your organisation? Please contact

Blog | MVP profile | Twitter


Xamarin Experts
Windows 10 Experts

You may also be interested in...

Pro
Pro

Comments and Discussions

 
SuggestionXamarin Forms XAML intellisense is possible with this extension Pin
Mobile Dan27-Mar-15 6:20
memberMobile Dan27-Mar-15 6:20 
SuggestionMinor edits to an amazing article Pin
Mobile Dan27-Mar-15 6:05
memberMobile Dan27-Mar-15 6:05 
GeneralRe: Minor edits to an amazing article Pin
Daniel Vaughan27-Mar-15 11:29
memberDaniel Vaughan27-Mar-15 11:29 
GeneralMy vote of 5 Pin
Steve Solomon18-Sep-14 1:18
memberSteve Solomon18-Sep-14 1:18 
GeneralRe: My vote of 5 Pin
Daniel Vaughan18-Sep-14 1:20
memberDaniel Vaughan18-Sep-14 1:20 
GeneralMy vote of 5 Pin
Steve Solomon18-Sep-14 1:16
memberSteve Solomon18-Sep-14 1:16 
GeneralMy vote of 5 Pin
Paulo Zemek17-Sep-14 15:52
professionalPaulo Zemek17-Sep-14 15:52 
GeneralRe: My vote of 5 Pin
Daniel Vaughan17-Sep-14 23:47
memberDaniel Vaughan17-Sep-14 23:47 
QuestionXamarin & Calcium for Metro? Pin
Dewey17-Sep-14 6:25
memberDewey17-Sep-14 6:25 
AnswerRe: Xamarin & Calcium for Metro? Pin
Daniel Vaughan17-Sep-14 7:37
memberDaniel Vaughan17-Sep-14 7:37 
GeneralRe: Xamarin & Calcium for Metro? Pin
Dewey20-Sep-14 1:25
memberDewey20-Sep-14 1:25 
GeneralMy vote of 5 Pin
priti@cp15-Sep-14 21:06
memberpriti@cp15-Sep-14 21:06 
GeneralRe: My vote of 5 Pin
Daniel Vaughan16-Sep-14 2:28
memberDaniel Vaughan16-Sep-14 2:28 
QuestionGood stuff Daniel! Pin
Volynsky Alex15-Sep-14 10:19
professionalVolynsky Alex15-Sep-14 10:19 
Thumbs Up | :thumbsup: Thumbs Up | :thumbsup: Thumbs Up | :thumbsup:
AnswerRe: Good stuff Daniel! Pin
Daniel Vaughan15-Sep-14 13:22
memberDaniel Vaughan15-Sep-14 13:22 
QuestionRe: Good stuff Daniel! Pin
Volynsky Alex16-Sep-14 9:07
professionalVolynsky Alex16-Sep-14 9:07 
Questiongood effort Pin
Sacha Barber15-Sep-14 5:15
mvpSacha Barber15-Sep-14 5:15 
AnswerRe: good effort Pin
Daniel Vaughan15-Sep-14 8:44
memberDaniel Vaughan15-Sep-14 8:44 
GeneralGreat series Pin
Katka Vaughan15-Sep-14 3:45
memberKatka Vaughan15-Sep-14 3:45 
GeneralRe: Great series Pin
Sacha Barber15-Sep-14 5:14
mvpSacha Barber15-Sep-14 5:14 
QuestionEnough with the teasers... Pin
Pete O'Hanlon15-Sep-14 3:04
protectorPete O'Hanlon15-Sep-14 3:04 
AnswerRe: Enough with the teasers... Pin
Daniel Vaughan15-Sep-14 3:50
memberDaniel Vaughan15-Sep-14 3:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170915.1 | Last Updated 15 Sep 2014
Article Copyright 2014 by Daniel Vaughan
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid