question

KevinDelval avatar image
0 Votes"
KevinDelval asked KevinDelval answered

Reusable ResourceDictionaries with Overrides

Hello,

I was hoping someone might be able to help me with this.

I am attempting to create a flexible Styles library where I can define a number of default styles for various controls, using default variables for padding, margin, color, etc. However, I want to be able to override these variables or even the styles themselves in apps that use the resource dictionaries from that external library. Basically, I get a kind of generic look-and-feel across all my apps, but if I define another Color with x:Key="PrimaryColor" I want the styles from those external resource dictionaries to use that color instead (naturally, the keys have to be the same).

I have already created some test .xaml files with a code-behind that inherit from ResourceDictionary and define some test values for Thickness. I am able to reference these in my app and apply them to views. However, the following results in a XamlParseException (StaticResource not found for key ThicknessValueNormal):

 <!-- Thickness.xaml -->
    
 <?xml version="1.0" encoding="UTF-8" ?>
 <ResourceDictionary x:Class="Sigma.XF.Theming.Variables.Thickness"
                     xmlns="http://xamarin.com/schemas/2014/forms"
                     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <!--  All  -->
  <Thickness x:Key="ThicknessNormal"
             Bottom="{StaticResource ThicknessValueNormal}"
             Left="{StaticResource ThicknessValueNormal}"
             Right="{StaticResource ThicknessValueNormal}"
             Top="{StaticResource ThicknessValueNormal}" />
 </ResourceDictionary>
    
 <!-- Spacings.xaml -->
    
 <?xml version="1.0" encoding="UTF-8" ?>
 <ResourceDictionary x:Class="Sigma.XF.Theming.Variables.Spacings"
                     xmlns="http://xamarin.com/schemas/2014/forms"
                     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <!--  Padding/Margin  -->
  <x:Double x:Key="ThicknessValueMini">5.0</x:Double>
  <x:Double x:Key="ThicknessValueSmall">10.0</x:Double>
  <x:Double x:Key="ThicknessValueNormal">15.0</x:Double>
  <x:Double x:Key="ThicknessValueLarge">25.0</x:Double>
  <x:Double x:Key="ThicknessValueXLarge">35.0</x:Double>
  <x:Double x:Key="ThicknessValueHuge">50.0</x:Double>
    
    
  <!--  Spacing  -->
  <x:Double x:Key="SpacingMini">5.0</x:Double>
  <x:Double x:Key="SpacingSmall">10.0</x:Double>
  <x:Double x:Key="SpacingNormal">15.0</x:Double>
  <x:Double x:Key="SpacingLarge">20.0</x:Double>
  <x:Double x:Key="SpacingXLarge">25.0</x:Double>
  <x:Double x:Key="SpacingHuge">30.0</x:Double>
    
  <x:Double x:Key="SpacingButtonMini">48.0</x:Double>
  <x:Double x:Key="SpacingButtonSmall">36.0</x:Double>
  <x:Double x:Key="SpacingButtonNormal">24.0</x:Double>
  <x:Double x:Key="SpacingButtonLarge">12.0</x:Double>
  <x:Double x:Key="SpacingButtonXLarge">8.0</x:Double>
  <x:Double x:Key="SpacingButtonHuge">4.0</x:Double>
 </ResourceDictionary>


 <FlyoutPage.Detail>
  <ContentPage Title="Test">
  <StackLayout BackgroundColor="Red">
  <ContentView BackgroundColor="Blue"
   VerticalOptions="CenterAndExpand">
  <Label BackgroundColor="Magenta"
     HorizontalOptions="Center"
     Padding="{StaticResource ThicknessNormal}"
         Text="Test" />
  </ContentView>
  </StackLayout>
  </ContentPage>
  </FlyoutPage.Detail>

When I attempt to use ThicknessNormal, it is unable to find ThicknessValueNormal. I can solve this by adding a reference to the Spacings.xaml in Thickness.xaml, but then I am no longer able to override those doubles in an app actually making use of these styles, as the resource lookup mechanism will always prioritize the locally declared keys over any external ones.

As far as I can tell, it seems that the ResourceDictionary's lookup does not reach my App.Xaml, where I proceed to merge both the Spacings.xaml and Thickness.xaml files:

 <?xml version="1.0" encoding="utf-8" ?>
 <Application x:Class="Sigma.XF.Sample.App"
              xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              xmlns:variables="clr-namespace:Sigma.XF.Theming.Variables;assembly=Sigma.XF">
  <Application.Resources>
  <ResourceDictionary>
  <ResourceDictionary.MergedDictionaries>
  <!--  Variables  -->
  <variables:Spacing />
  <variables:Thickness />
    
  <!--  This is where I would like to define overrides for colors, spacings, margins, etc.  -->
  </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
  </Application.Resources>
 </Application>


Now the question is: is there something I am overlooking or is what I am attempting to do simply not possible? I know one fix would be to simply copy all the resource dictionary xamls and just change whatever values I need different for a specific app, but that doesn't really solve the issue of wanting to prevent code duplication, since any updates I make to the style library will need to be copied over again (and changed values reset).

Thanks in advance.

EDIT:

What I mean is that I would like to be able to declare an <x:Double> with the same Key but a different value in an app making use of those styles, thereby changing the defaults. So I can solve the runtime XamlParseException by doing the following:

 <?xml version="1.0" encoding="UTF-8" ?>
  <ResourceDictionary x:Class="Sigma.XF.Theming.Variables.Thickness"
                      xmlns="http://xamarin.com/schemas/2014/forms"
                      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
       <ResourceDictionary.MergedDictionaries>
         <variables:SpacingsDictionary />
     </ResourceDictionary.MergedDictionaries>
    
      <!--  All  -->
      <Thickness x:Key="ThicknessNormal"
                 Bottom="{StaticResource ThicknessValueNormal}"
                 Left="{StaticResource ThicknessValueNormal}"
                 Right="{StaticResource ThicknessValueNormal}"
                 Top="{StaticResource ThicknessValueNormal}" />
  </ResourceDictionary>

But if I do this, then ThicknessNormal will only ever use the value with key ThicknessValueNormal from the Spacings.xaml file. So, in an app using this style library, I am no longer able to redefine a Thickness with the same key, but a different value.
A better use case would be with colors, where I might want different primary and secondary colors, but I want all my styles imported from that external library to function as normal, using those new colors.

dotnet-xamarinforms
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

What do you mean by words but then I am no longer able to override those doubles in an app actually making use of these styles?

0 Votes 0 ·

I have edited my original question with an elaboration to answer yours.

0 Votes 0 ·

When resources share keys, resources defined lower in the visual tree will take precedence over those defined higher up. So, you can define resource in lower level of visual tree. For more details, check: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/resource-dictionaries#override-resources .

1 Vote 1 ·

Since you have defined a ThicknessNormal.xaml, but why would you want to redefine one in Application.xaml? Since we could define and utilize some global resource in Application.xaml, I don't think it's necessary to redefine the same.

0 Votes 0 ·
Show more comments

1 Answer

KevinDelval avatar image
0 Votes"
KevinDelval answered

I've managed to find a solution to the problem.

The use of DynamcResources actually solved the issue quite nicely. I wasn't aware of how they worked. But they allow me to define optional defaults on a variety of variables (colors, thicknesses, etc) which can then be included, overriden or left out entirely whenever I want to reuse these styles.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.