C#, Resources, Xaml, Xamarin.Forms

Adding Themes to Xamarin.Forms App

I just want to make some short notes about themes in Xamarin.Forms Apps, since there are already a lot of tutorials available online, that go way deeper.

Themes
Themes are actually ResourceDictionaries. Each atomic type you use in your XAMLs and Styles, will be defined here. Types are f.e. Color, Double (for font sizes), etc.

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ShoppingList.Themes.DarkTheme">
    <Color x:Key="BackgroundColor">#333333</Color>
    <Color x:Key="TextColor">#eeeeee</Color>
    <Color x:Key="PlaceholderTextColor">#55ffffff</Color>
    <Color x:Key="ControlBackground">#111111</Color>
    <Color x:Key="ButtonBackgroundColor">#11ffffff</Color>
</ResourceDictionary>

Be sure to have a code behind file for your ResourceDictionary, that calls InitializeComponent(). Otherwise this will only work on UWP (without .NET Toolchain) and no other platforms.

Styles
In most cases the styles are not part of your themes, because using themes just makes you change the look of your pages and controls, not the styling of specific controls. Perhaps styles are using the resources, that you define in your theme. Be sure to use DynamicResource for linking to the key of the resource, otherwise you can not change themes during runtime. (Restart will be needed)

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ShoppingList.Resources.Styles">
    <Style TargetType="NavigationPage">
            <Setter Property="BackgroundColor" Value="{DynamicResource BackgroundColor}"/>
            <Setter Property="BarBackgroundColor" Value="{DynamicResource BackgroundColor}"/>
            <Setter Property="BarTextColor" Value="{DynamicResource TextColor}"/>
            
        </Style>
        <Style TargetType="Label">
            <Setter Property="TextColor" Value="{DynamicResource TextColor}" />
        </Style>
        <Style TargetType="Entry">
            <Setter Property="BackgroundColor" Value="{DynamicResource ControlBackground}" />
            <Setter Property="TextColor" Value="{DynamicResource TextColor}" />
            <Setter Property="PlaceholderColor" Value="{DynamicResource PlaceholderTextColor}" />
        </Style>
        <Style TargetType="Button">
            <Setter Property="TextColor" Value="{DynamicResource TextColor}" />
            <Setter Property="BackgroundColor" Value="{DynamicResource ButtonBackgroundColor}" />
            
        </Style>
</ResourceDictionary>

Changing the theme
Now you just need to add the following code to your App.xam.cs, then you can just call App.SetTheme(typeof(DarkTheme)) to change the theme during runtime.

Be sure to add all your style-ResourceDictionaries and a standard theme to your App.xaml in the Application.Resources-Section

internal static void SetTheme(Type themeType)
{
   Preferences.Set("Theme", themeType.FullName);
   var resDict = (ResourceDictionary)Activator.CreateInstance(themeType);
   App.Current.Resources.MergedDictionaries.Add(resDict); // this line replaces all keys of the current dictionary with the value of the selected dictionary, only the keys that are present in the selected dictionary will be replaced
}

In your “OnInitialize” method of your App.xaml.cs you can put the following code, to load the saved theme on startup:

if (Preferences.ContainsKey("Theme"))
{
   var themeTypeName = Preferences.Get("Theme",null);
   var themeType = Type.GetType(themeTypeName);
   if (themeType != null)
   {
      SetTheme(themeType);
   }
}
.Net native, C#, Resources, Xaml

Problem with ResourceDictionary in Xamarin Forms .Net Native

Last week a colleague had the idea, to split the Resources, that we have defined in App.xaml in several ResourceDictionaries. Since our App.xaml has grown to over 400 lines, we thought this would be a very good idea, and did it as always:

 <Application.Resources>
        <ResourceDictionary xmlns:local="clr-namespace:TestResources">
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Resources/Buttons.xaml" />
                <ResourceDictionary Source="/Resources/Labels.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

Looks good, and when we were testing the App, it worked well. But as soon, as we wanted to ship the App to our customer, it totally crashed during start up. What was the difference? We always test Debug builds, but without .Net Native
Toolchain active, but for shipping, we made a Release build with .Net Native builds activated.

The following error occured:

Unhandled exception at 0x05B6B264 (Windows.UI.Xaml.dll) in TestResources.UWP.exe: 0xC000027B: Anwendungsinterne Ausnahme (parameters: 0x0B477CF8, 0x00000003).

In the output window we see a lot of error messages:

Unhandled exception at 0x05B4B264 (Windows.UI.Xaml.dll) in TestResources.UWP.exe: 0xC000027B: internal error(parameters: 0x0B44D9B0, 0x00000003).

Unhandled exception at 0x777AF989 (combase.dll) in TestResources.UWP.exe: 0xC0000602: Ein sofortiger Ausnahmefehler ist aufgetreten. Die Ausnahmehandler werden nicht aufgerufen, und der Prozess wird sofort beendet.

Unhandled exception at 0x77627ED3 (combase.dll) in TestResources.UWP.exe: 0xC0000005: Access violation reading location 0x00000008.

I am not quite sure, why this happens but the solution is quite simple:

  • Add a code behind file (in our case Buttons.cs).
  • In the constructor, call “InitializeComponent()”.
  • Now we can include the ResourceDictionary directly in the App.xaml
  • In our case the Buttons.xaml.cs looks like this:

       public partial class Buttons : ResourceDictionary
        {
            public Buttons()
            {
                InitializeComponent();
            }
        }
    

    ..and the App.xaml

    <Application.Resources>
            <ResourceDictionary xmlns:local="clr-namespace:TestResources">
                <ResourceDictionary.MergedDictionaries>
                    <local:Buttons />
                    <!--<ResourceDictionary Source="/Resources/Buttons.xaml" />-->
                    <!--<ResourceDictionary Source="/Resources/Labels.xaml" />-->
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Application.Resources>
    

    If you have a clue, why we need to go this way, just leave me a comment.