Global resources in Xamarin Forms! No App.xaml? Create one!

Xaml developers moving to Xamarin Forms are hoping to take some of their good habits from the Windows (WPF/Silverlight/UWP) dev world with them. And probably a few of their bad ones as well but we don't want to talk about those. But sometimes the constructs the devs hope to find in Xamarin Forms are not there waiting for them by default. Such is was the case with App.Xaml.

little bo peep

Declaring resources such as strings and styles (Resource Dictionaries) at an application level is a good thing.  App.xaml is a construct that enables us to declare global styles, strings, and resources in a declarative fashion, aka using XML and not C#. In fact, the only thing that can be put into the body of the App.xaml declaration is Application.Resources declarations ( see https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.resources.aspx  ) for details on Application level resources.

App.xaml was not a default item in a Xamarin Forms PCL Template before version 4.1.  In lieu of App.xaml, Xamarin Forms would put an App.cs into the project for application level code and resource declarations. Even in Xamarin 4.1, the Blank Xamarin Forms ( Portable Class Library ) template still gives us an App.cs file, and not an App.Xaml file.  A blog post by Falafel gives us a great example of using code (C#) inside App.cs to create global level resources( https://blog.falafel.com/creating-global-resources-for-xamarin-forms-apps/ ).
Read the post to get an idea of what I mean.  Definitely not XML declarations.

But... Xaml devs often want to define resources using declarative layouts (XML)  and not code ( C# ).

I'm going to show you how to add an App.xaml to an existing Xamarin Forms project using a Xaml based approach. If you want a non-declarative, code-driven approach, Falafel's approach is great. Please stop reading this blog post immediately and surf to Falafel's page.

NOTE: If you are using Xamarin Forms 4.1 or later, and creating a new project, you should start new Xamarin Forms projects with the Blank Xaml App ( Xamarin.Forms Portable ) instead of the Blank App ( Xamarin.Forms Portable ) . I'll detail the differences in a future post, but suffice it to say that the Blank Xaml App template in Xamarin 4.1 uses a full App.xaml as a default file in the template, versus pre 4.1 App.cs.

Follow the steps below to add App.xaml to an existing Xamarin Forms project.

SETUP OUR APP.XAML

  • Create a Blank App ( Xamarin.Forms Portable ) in Visual Studio and name it "HelloXamarinForms"
  • Rename App.cs to App.cs.saveme - this is a precautionary measure for us "just in case"
  • Add a new Xaml form to the page and name it "App.xaml"
  • Modify App.xaml.cs so that the class App inherits from Application
  • Add a call to InitializeComponent() to the constructor
  • Modify the App.MainPage initialization line to point to a new startup page we will created named UseGlobalResourceDictPage.xaml .

App.xaml.cs

 public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        MainPage = new UseGlobalResourceDictPage(); 
    }
...
}

ADD GLOBAL RESOURCES

  • Modify App.xaml to resemble the following. This is our application level resource dictionary.

App.xaml

 <Application xmlns="https://xamarin.com/schemas/2014/forms"
            xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
            x:Class="HelloXamarinForms.App">
<Application.Resources>
<ResourceDictionary>
    <Color x:Key="PageBackgroundColor">Yellow</Color>
    <Color x:Key="HeadingTextColor">Black</Color>
    <Color x:Key="NormalTextColor">Blue</Color>
    <Style x:Key="LabelPageHeadingStyle" TargetType="Label">
        <Setter Property="FontAttributes" Value="Bold" />
        <Setter Property="HorizontalOptions" Value="Center" />
        <Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
    </Style>
</ResourceDictionary>
</Application.Resources>
</Application>

USE GLOBAL RESOURCES

  • Add a new Xaml form called "UseGlobalResourceDictPage" to our project
  • Modify the Xaml of UseGlobalResourceDictPage to match the following. Note the use of StaticResources applying
    styles to our Buttons and Labels.

UseGlobalResourceDictPage.xaml

 <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="https://xamarin.com/schemas/2014/forms"
             xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloXamarinForms.ResDictUseApplicationLevelPage">
    <StackLayout>
    <StackLayout.Resources>
      <ResourceDictionary>
        <Style x:Key="LabelNormalStyle" TargetType="Label">
          <Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
        </Style>
        <Style x:Key="MediumBoldText" TargetType="Button">
          <Setter Property="FontSize" Value="Medium" />
          <Setter Property="FontAttributes" Value="Bold" />
        </Style>
      </ResourceDictionary>
    </StackLayout.Resources>
    <Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
    <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
           Style="{StaticResource LabelNormalStyle}" />
    <Button Text="Navigate" 
            TextColor="{StaticResource NormalTextColor}"
            HorizontalOptions="Center"
            Style="{StaticResource MediumBoldText}" />
  </StackLayout>
</ContentPage>

ENJOY

Give the page a run. We will see the styles and resources we have defined globally applied to
our Xaml form layout. Screenshots shown below for UWP and Android. Too lazy to get my Mac out of my backpack (yes, I'm on the road).
screen shots
Have fun and enjoy. Feedback is welcome. This is blogged cause I couldn't find a public blog on how to do this anywhere. Feel free to post more links to aid in the App.xaml quest for Xamarin forms.

RESOURCES

Comments

  • Anonymous
    August 23, 2016
    Thre is no xaml forms found.
  • Anonymous
    May 22, 2017
    At this moment doesn't work with navigantion MainPage = new NavigationPage(new MainPage());