Styles that are based upon other styles that span multiple files

Viewed 831

How can I use Style Inheritance w/ multiple files? I've been able to utilize Stand-alone resource dictionaries but if a child style is BasedUpon a style in another file it isn't working.

In the example below, the ListView will have the specified SeparatorColor but not the BackgroundColor from the BasedUpon style.

BaseStyles.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <Color x:Key="LightPrimaryColor">LightPink</Color>
    <Color x:Key="DarkPrimaryColor">DarkGreen</Color>
    <Style x:Key="BaseColorStylePrimary" TargetType="View">
        <Setter Property="BackgroundColor"
                Value="{AppThemeBinding Light={StaticResource LightPrimaryColor}, Dark={StaticResource DarkPrimaryColor}}" />
    </Style>
</ResourceDictionary>

SomeChildStyles.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <Style x:Key="ListViewStyleBasedOn"
           TargetType="ListView"
           BasedOn="{StaticResource BaseColorStylePrimary}">
        <Setter Property="SeparatorColor"
                Value="{AppThemeBinding Light=Orange, Dark=Red}" />
    </Style>
</ResourceDictionary>

App.xaml

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StyleInheritance.App">
    <Application.Resources>
        <ResourceDictionary Source="BaseStyles.xaml" />
        <ResourceDictionary Source="SomeChildStyles.xaml" />
    </Application.Resources>
</Application>

It looks like they made some changes a few years ago to achieve what I'm trying to do but when they introduced AppThemeBinding it wasn't expanded to handle this ?

2 Answers
  1. Add a code behind file w/ a call to InitializeComponent() to each separate resource file even though this blog post says it is no longer required.
  2. Don't use the fancy clean way to remove extra code for defining <ResourceDictionary>'s

Updated BaseStyles.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    <!--change is here-->
                    x:Class="StyleInheritance.BaseStyles">
    <Color x:Key="LightPrimaryColor">LightPink</Color>
    <Color x:Key="DarkPrimaryColor">DarkGreen</Color>
    <Style x:Key="BaseColorStylePrimary" TargetType="View">
        <Setter Property="BackgroundColor"
                Value="{AppThemeBinding Light={StaticResource LightPrimaryColor}, Dark={StaticResource DarkPrimaryColor}}" />
    </Style>
</ResourceDictionary>

BaseStyles.xaml.cs

using Xamarin.Forms;
namespace StyleInheritance
{
    public partial class BaseStyles : ResourceDictionary
    { public BaseStyles() { InitializeComponent(); } }
}

SomeChildStyles.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    <!--change is here-->
                    x:Class="StyleInheritance.SomeChildStyles">
    <Style x:Key="ListViewStyleBasedOn"
           TargetType="ListView"
           BasedOn="{StaticResource BaseColorStylePrimary}">
        <Setter Property="SeparatorColor"
                Value="{AppThemeBinding Light=Orange, Dark=Red}" />
    </Style>
</ResourceDictionary>

Added SomeChildStyles.xaml.cs

using Xamarin.Forms;
namespace StyleInheritance
{
    public partial class SomeChildStyles : ResourceDictionary
    { public SomeChildStyles() { InitializeComponent(); } }
}

App.xaml

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StyleInheritance.App">
    <Application.Resources>
        <!--change is here-->
        <ResourceDictionary>
            <ResourceDictionary Source="BaseStyles.xaml" />
            <ResourceDictionary Source="SomeChildStyles.xaml" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

I've created a full Sample project w/ some additional details in the readme.

Use MergedDictionaries to style with multiple files.

App.xaml:

<Application.Resources>
  <ResourceDictionary>
    <!--Global Styles-->
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="/Styles/Base.xaml" />
      <ResourceDictionary Source="/Styles/Child.xaml" />
    </ResourceDictionary.MergedDictionaries>
    ...
  </ResourceDictionary>
</Application.Resources>

Base.xaml in folder Styles:

<?xml version="1.0" encoding="utf-8" ?>
<!--<?xaml-comp compile="true" ?>-->
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <Style x:Key="BaseStyle" TargetType="Label">
    <Setter Property="BackgroundColor" Value="Green" />
  </Style>
</ResourceDictionary>

Child.xaml in folder Styles:

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <Style x:Key="ChildStyle" TargetType="Label" BasedOn="{StaticResource BaseStyle}">
    <Setter Property="FontAttributes" Value="Italic" />
  </Style>
</ResourceDictionary>

Sample XAML usage:

<Label Text="Background" Style="{StaticResource BaseStyle}"/>
<Label Text="Background+Italic" Style="{StaticResource ChildStyle}"/>

See also Better Resource Organization in Xamarin.Forms

Edit:

To use a Xaml ResourceDictionary without a partial class (code behind class) (as indicated by the x:Class attribute), remove the code behind class .xaml.cs file and the x:Class attribute. Please note that the property Build Action should be Embedded resource.

The properties should be observed in the project file:

<ItemGroup>
  <EmbeddedResource Update="Styles\Child.xaml">
    <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
    <!--<Generator>MSBuild:Compile</Generator>-->
  </EmbeddedResource>
  <EmbeddedResource Update="Styles\Base.xaml">
    <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
    <!--<Generator>MSBuild:Compile</Generator>-->
  </EmbeddedResource>
</ItemGroup>
Related