Creating a Xamarin Forms App Part 4 : Application Resources

  • Part 1 : Introduction
  • Part 2 : Getting Started
  • Part 3 : How to use Xamarin Forms with Visual Studio without the Business Edition
  • Part 4 : Application Resources
  • Part 5 : Dependency Injection
  • Part 6 : View Model First Navigation
  • Part 7 : Unit Testing
  • Part 8 : Consuming a RESTful Web Service
  • Part 9 : Working with Alerts and Dialogs
  • Part 10 : Designing and Developing the User Interface
  • Part 11 : Updating to Xamarin Forms 1.3
  • Part 12 : Extending the User Interface

Although Xamarin Forms shares many similarities with WPF it currently does not support Application resources that can be shared across the application. Fortunately Corrado Cavalli provides us with a very nice solution here.

I have modified his solution slightly as I want to place the shared classes in my Core project. This blog post will show you how to do this.

In the Core project we created in Part 2, create a class called App.cs with the following code.

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

namespace Silkweb.Mobile.Core
{
    public class App : BindableObject
    {
        public App()
        {
            Current = this;
        }

        public ResourceDictionary Resources { get; set; }

        public static App Current { get; protected set; }

        public Page MainPage { get; set; }
    }
}

Notice here that I am deriving directly from BindableObject rather than View because my App class doesn’t need all the extra bloat that comes with View. It includes two instance properties, Resources and Main Page and a static Current property. Also notice that the constructor sets the Current property to it self.

In the applications shared PCL (e.g. Silkweb.Mobile.MountainForecast) we need to create an App class that will inherit from the Core App class above but we also want it to contain a Xaml page where we can declare our Application Resources.

First delete the App class in the application shared PCL and then select Add > New File and then choose Forms ContentView Xaml from the Forms category. Name this file the name of your application with an App suffix. e.g. MountainForecastApp.

1

The reason I want to name it like this rather than simply App is to avoid any confusion with our Core App class and it clearly advertises what it is. In the code behind cs file update the class to inherit from the Core App class rather than ContentView and set the MainPage in the constructor like this:

    public partial class MountainForecastApp : App
    {    
        public MountainForecastApp()
        {
            InitializeComponent();

            MainPage = new NavigationPage(new MainPage
                {
                    BindingContext = new MainViewModel()
                });
        } 

        public new static App Current
        {
            get { return App.Current ?? new MountainForecastApp();  }
        }
    }

Notice here I am providing a new implementation of the static Current property that creates our new MountainForecastApp. The reason the App base class also has a static Current property is so that we can reference the Current instance from our Core project without needing to know about the derived type.

Next we need to update the MountainForecastApp.xaml file to also inherit from App. To do this we need to add a namespace reference to our Core project and then update the file like this.

<?xml version="1.0" encoding="UTF-8"?>
<core:App 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:core="clr-namespace:Silkweb.Mobile.Core;assembly=Silkweb.Mobile.Core" 
    x:Class="Silkweb.Mobile.MountainForecast.MountainForecastApp">
    <core:App.Resources>
        <ResourceDictionary>
            <Color x:Key="textColor">Red</Color>
        </ResourceDictionary>
    </core:App.Resources>
</core:App>

Notice here the core: namespace prefix. I have also added a Resource Dictionary to the App.Resources which contains one simple Color resource named textColor.

As we have now changed the App class we also need to update the iOS and Android projects to use our new MountainForecastApp class.

In the iOS project update the AppDelegate class to set the RootViewController to:

     window.RootViewController = MountainForecastApp.Current.MainPage.CreateViewController();

Then in the Android project update the MainActivity class SetPage to:

     SetPage(MountainForecastApp.Current.MainPage);

If you build the solution at this point you will get some crazy errors, which are not actually errors.

2

I blogged about this in Part 2 here. Ignore them if you can, or close and re-open Xamarin Studio and they will go away.

Now we need a Xaml markup extension to lookup our resources. This follow’s Step 6 in Corrado’s blog. We however are going to add this to our Core project. Create a folder in the Core project called Extensions and add the following ApplicationResourceExtension class.

namespace Silkweb.Mobile.Core.Extensions
{
    [ContentProperty(&amp;quot;Key&amp;quot;)]
    public class ApplicationResourceExtension : BindableObject, IMarkupExtension
    {
        public string Key { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Key == null)
                throw new InvalidOperationException(&quot;you must specify a key in {GlobalResource}&quot;);

            if (serviceProvider == null)
                throw new ArgumentNullException(&quot;serviceProvider&quot;);

            object value;

            bool found = App.Current.Resources.TryGetValue(Key, out value);

            if (found) return value;

            throw new ArgumentNullException(string.Format(&quot;Can't find a global resource for key {0}&quot;, Key));
        }
    }
}

Note the App.Current.Resources here is our Core App, not the derived one.

Now lets use this in our MainPage. Add the following Xaml to the MainPage.Xaml in the application shared PCL project.

<?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="Silkweb.Mobile.MountainForecast.Views.MainPage"
    xmlns:e="clr-namespace:Silkweb.Mobile.Core.Extensions;assembly=Silkweb.Mobile.Core"
    Title="{Binding Title}">

    <Label Text="{Binding Forecast}" TextColor="{e:ApplicationResource textColor}" />

</ContentPage>

Notice we have added a namespace to reference the Core.Extensions with the e: prefix. Then we set the TextColor of the Label to the textColor resource using the ApplicationResource markup extension.

Build and run the App and you should see the Text displayed in Red.

3

The great thing about this is we now have a nice neat place to put many of the resources we are going to need and have a simple way to reference them.

In later posts I will be adding further features to the Core App class and provide a better way to bootstrap the Application with a Dependency Injection Container. For now though I hope you found this post useful.

8 thoughts on “Creating a Xamarin Forms App Part 4 : Application Resources

  1. In this step if we create an App class derived from BindableObject, and then we derive our MountainForecastApp class from that App class, where could InitializeComponent() and MainPage possibly come from? I’m wondering if maybe you didn’t quite translate what you did to the article here.

    Like

  2. Oops, I’m looking at the source code and it’s making more sense now. Part of my confusion came from the fact that there is not (or at least there isn’t now) a Visual Studio template for “Forms ContentView Xaml”. Anyway, thanks for your excellent articles!

    Like

  3. I’m taking another stab at this, and I’ve come up with a question:
    Have you attempted to update this for the newer Forms framework?
    For instance, Android’s SetPage is now obsolete. Both Android and iOS now use LoadApplication,

    Like

  4. Hmm…it looks like the new Application class allows sharing resources, so your answer to that may not be necessary anymore? I guess I’m now wondering how that would simplify things in terms of your app…

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s