How do I reference one XAML MergedDictionary from another?

EasyGoingPatEasyGoingPat GBMember ✭✭✭

I am struggling with XAML Merged Dictionaries. Is it possible to get something like the following working?

File Colours.xaml contains this:

<?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">

    <Color x:Key="WarningTextColour">#FF0000</Color>

</ResourceDictionary>

Another file Text.xaml contains something like this:

<?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="WarningTextStyle" TargetType="Label">
        <Setter Property="TextColor" Value="{StaticResource WarningTextColour}"/>
        <Setter Property="FontSize" Value="Large"/>
    </Style>
</ResourceDictionary>

Then somewhere like my main App.xaml file, I bring them together like this:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="myProject.Forms.App">

    <Application.Resources>
        <ResourceDictionary Source="Styles/Colours.xaml"/>
        <ResourceDictionary Source="Styles/Text.xaml"/>
    </Application.Resources>

</Application>

I've read the guides and tried various combinations of syntax, trying both the old and the new ways, but I can't find a way to do this. I am beginning to wonder if I am maybe approaching this completely the wrong way.

Even with all my XAML set to compile, the project builds okay (which is disappointing if I have something wrong), but the MainPage.xaml that tries to use the WarningTextStyle gives an exception.

Any help or advice would be very much appreciated.

Kind wishes ~ Patrick

Best Answers

  • EasyGoingPatEasyGoingPat GB ✭✭✭
    Accepted Answer

    Having read everything there is to read about Xamarin's latest incarnation of Merged Resource Dictionaries in XAML and finding myself still having to experiment before I came up with a structure I was happy with, I thought another example wouldn't go amiss. Below, I describe the way I have organised my Resource Dictionaries. It compiles and runs and is fairly complete, at least as far as is relevant for this topic. I hope it proves useful to someone.

    My original question was about using multiple Merged Resource Dictionaries. Thanks to the work of the Xamarin team, this is now fairly easy but there is one thing you can't do (which I was trying to do) so I'll start with that to stop anyone wasting time on the same mistake I was making.

    DON'T do this:

    I had a Colours.xaml file, and I wondered if I could then create other Resource Dictionaries and make references between them, like this.

    Colours.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Color x:Key="Colour1">#00043F</Color>
        <Color x:Key="Colour2">#FF043F</Color>
    </ResourceDictionary>
    

    Buttons.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Style x:Key="ButtonStyle1" TargetType="Button">
            <Setter Property="TextColor" Value="{StaticResource Colour1}"/>
        </Style>
    </ResourceDictionary>
    

    Labels.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Style x:Key="LabelStyle1" TargetType="Label">
            <Setter Property="TextColor" Value="{StaticResource Colour2}"/>
        </Style>
    </ResourceDictionary>
    

    And then in my App.xaml file, I tried to pull them together like this:

    <Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MyProject.Forms.App">
        <Application.Resources>
            <ResourceDictionary Source="Styles/Colours.xaml"/>
            <ResourceDictionary Source="Styles/Buttons.xaml"/>
            <ResourceDictionary Source="Styles/Labels.xaml"/>
        </Application.Resources>
    </Application>
    

    The example above does not work! It is asking a bit much. Basically, I am asking the system to behave like the C++ header-file processor, which concatenates all header files and allows you to write code as if it were all in one big single file. The system probably could work this way, but I am sure someone who knows more theory than I do can tell me why this would be a really bad idea.

    So how does it work?

    It turns out that what I have above is not too far away from the solution. You just have to be more explicit about which XAML files reference which other ones. So, to get what I have above working, it becomes this:

    Colours.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Color x:Key="Colour1">#00043F</Color>
        <Color x:Key="Colour2">#FF043F</Color>
    </ResourceDictionary>
    

    Buttons.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Colours.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="ButtonStyle1" TargetType="Button">
            <Setter Property="TextColor" Value="{StaticResource Colour1}"/>
        </Style>
    </ResourceDictionary>
    

    Labels.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Colours.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="LabelStyle1" TargetType="Label">
            <Setter Property="TextColor" Value="{StaticResource Colour2}"/>
        </Style>
    </ResourceDictionary>
    

    App.xaml

    <Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MyProject.Forms.App">
        <Application.Resources>
            <ResourceDictionary Source="Buttons.xaml"/>
            <ResourceDictionary Source="Labels.xaml"/>
        </Application.Resources>
    </Application>
    

    Notice the change. In my Buttons.xaml and Labels.xaml, I now explicitly merge in the Colours.xaml file, allowing me to use the colour definitions in those files. My App.xaml now no longer needs the Colours.xaml file to be merged in because it does not itself use these colour definitions. Of course, if you also wish to make use of colours in your App.xaml file, there is nothing to stop you bringing in the colours again. In other words, you can switch back to the first version of the App.xaml file above and everything still works fine.

    I have also tried doing this directly in a ContentPage and it all seems to work exactly the same. So, with a bit of thought, you can set up your structure for your whole application and then pull in specific stuff for individual pages, keeping the size of your main App.xaml dictionary down, which should help load time.

    Finally, all of this still works if you start putting XAML files into subfolders. So, for example, you can create a Styles/Colours.xaml and then reference it from the App.xaml like this:

    <Application.Resources>
        <ResourceDictionary Source="Styles/Colours.xaml"/>
    </Application.Resources>
    

    Folder paths are relative to each other, so if all three of my XAML resource files are in a Styles/ subfolder, they reference each other just using the file name Colours.xaml, not with the subfolder added (Styles/Colours.xaml).

    Hope all of this helps someone.

    If anything above is not clear, add a comment and I will try to clarify further.

  • EasyGoingPatEasyGoingPat GB ✭✭✭
    Accepted Answer

    @NMackay
    @tsgriggs2
    @AbhijitDeshpande

    This is a link to a small demo of how I set up my Xamarin MergedDictionaries. Hope it helps.
    https://1drv.ms/u/s!AjTIcJqQTWAFknJRxN97kpfk3gOR

    • Patrick
  • MartinBrekhofMartinBrekhof NL ✭✭
    edited November 2018 Accepted Answer

    Can be done:
    1. add the file with styles to your current project as a linked file
    2. make sure it has Build action (properties) defined as EmbeddedResource

    I added it to the root of my project (where app.xaml lives).

    hth
    Martin

Answers

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    Having read everything there is to read about Xamarin's latest incarnation of Merged Resource Dictionaries in XAML and finding myself still having to experiment before I came up with a structure I was happy with, I thought another example wouldn't go amiss. Below, I describe the way I have organised my Resource Dictionaries. It compiles and runs and is fairly complete, at least as far as is relevant for this topic. I hope it proves useful to someone.

    My original question was about using multiple Merged Resource Dictionaries. Thanks to the work of the Xamarin team, this is now fairly easy but there is one thing you can't do (which I was trying to do) so I'll start with that to stop anyone wasting time on the same mistake I was making.

    DON'T do this:

    I had a Colours.xaml file, and I wondered if I could then create other Resource Dictionaries and make references between them, like this.

    Colours.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Color x:Key="Colour1">#00043F</Color>
        <Color x:Key="Colour2">#FF043F</Color>
    </ResourceDictionary>
    

    Buttons.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Style x:Key="ButtonStyle1" TargetType="Button">
            <Setter Property="TextColor" Value="{StaticResource Colour1}"/>
        </Style>
    </ResourceDictionary>
    

    Labels.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Style x:Key="LabelStyle1" TargetType="Label">
            <Setter Property="TextColor" Value="{StaticResource Colour2}"/>
        </Style>
    </ResourceDictionary>
    

    And then in my App.xaml file, I tried to pull them together like this:

    <Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MyProject.Forms.App">
        <Application.Resources>
            <ResourceDictionary Source="Styles/Colours.xaml"/>
            <ResourceDictionary Source="Styles/Buttons.xaml"/>
            <ResourceDictionary Source="Styles/Labels.xaml"/>
        </Application.Resources>
    </Application>
    

    The example above does not work! It is asking a bit much. Basically, I am asking the system to behave like the C++ header-file processor, which concatenates all header files and allows you to write code as if it were all in one big single file. The system probably could work this way, but I am sure someone who knows more theory than I do can tell me why this would be a really bad idea.

    So how does it work?

    It turns out that what I have above is not too far away from the solution. You just have to be more explicit about which XAML files reference which other ones. So, to get what I have above working, it becomes this:

    Colours.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <Color x:Key="Colour1">#00043F</Color>
        <Color x:Key="Colour2">#FF043F</Color>
    </ResourceDictionary>
    

    Buttons.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Colours.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="ButtonStyle1" TargetType="Button">
            <Setter Property="TextColor" Value="{StaticResource Colour1}"/>
        </Style>
    </ResourceDictionary>
    

    Labels.xaml

    <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Colours.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="LabelStyle1" TargetType="Label">
            <Setter Property="TextColor" Value="{StaticResource Colour2}"/>
        </Style>
    </ResourceDictionary>
    

    App.xaml

    <Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MyProject.Forms.App">
        <Application.Resources>
            <ResourceDictionary Source="Buttons.xaml"/>
            <ResourceDictionary Source="Labels.xaml"/>
        </Application.Resources>
    </Application>
    

    Notice the change. In my Buttons.xaml and Labels.xaml, I now explicitly merge in the Colours.xaml file, allowing me to use the colour definitions in those files. My App.xaml now no longer needs the Colours.xaml file to be merged in because it does not itself use these colour definitions. Of course, if you also wish to make use of colours in your App.xaml file, there is nothing to stop you bringing in the colours again. In other words, you can switch back to the first version of the App.xaml file above and everything still works fine.

    I have also tried doing this directly in a ContentPage and it all seems to work exactly the same. So, with a bit of thought, you can set up your structure for your whole application and then pull in specific stuff for individual pages, keeping the size of your main App.xaml dictionary down, which should help load time.

    Finally, all of this still works if you start putting XAML files into subfolders. So, for example, you can create a Styles/Colours.xaml and then reference it from the App.xaml like this:

    <Application.Resources>
        <ResourceDictionary Source="Styles/Colours.xaml"/>
    </Application.Resources>
    

    Folder paths are relative to each other, so if all three of my XAML resource files are in a Styles/ subfolder, they reference each other just using the file name Colours.xaml, not with the subfolder added (Styles/Colours.xaml).

    Hope all of this helps someone.

    If anything above is not clear, add a comment and I will try to clarify further.

  • AbhijitDeshpandeAbhijitDeshpande INMember ✭✭

    I have an extended question, can we use the "Pure XAML ResourceDictionaries" (as mentioned in blog https://blog.xamarin.com/better-resource-organization-xamarin-forms/)

    If yes, what build action to specify when you don't have associated .cs file ?

    I just created the text file with extension .xaml (added the tag <?xaml-comp compile="true" ?>)
    but getting an compile error

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @AbhijitDeshpande

    In my example above, none of my resource dictionaries have a .cs file except, of course, the top-level Application dictionary. By setting the xaml-comp compile='true', as you say, it all works fine. What exactly is your error?

  • AbhijitDeshpandeAbhijitDeshpande INMember ✭✭

    Thanks @EasyGoingPat.

    This is pretty embarrassing. I did the steps again and its working as expected.
    May be needed your blessings.

    Cheers

  • tsgriggs2tsgriggs2 Member ✭✭
    edited September 2018

    I am struggling with this solution. For some reason, I get the following error, when building:

    "Position 7:25. Resource 'Resources/Styles/ColorStyles.xaml' not found."

    This is a new account, so I had to break the xmlns links in my code, below...

    My code is:

    ColorStyles.xaml

    <?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">
    
        <!-- Base Colors -->
        <Color x:Key="Black">#000000</Color>
        <Color x:Key="Beige">#FFF5F5DC</Color>
        <Color x:Key="Gray">#808080</Color>
        <Color x:Key="LightGray">#D9D9D9</Color>
        <Color x:Key="Transparent">#00000000</Color>
        <Color x:Key="White">#FFFFFF</Color>
    
    </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="iAssess.App">
    
      <Application.Resources>
        <ResourceDictionary Source="Resources/Styles/ColorStyles.xaml"/>
      </Application.Resources>
    
    </Application>
    

    App.xaml is on the same level as my Resources directory. ColorStyles.xaml is located in Resources/Styles.

    Any idea why I may be experiencing this? I have been stuck on it for hours and have never seen this issue before.

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @tsgriggs2

    Does the code you give above give you an error or do you get an error when you try to use the styles in a normal XAML page?

    (I'm going to struggle to help until next Wednesday because I am away from my development machine until then.)

    • Patrick
  • tsgriggs2tsgriggs2 Member ✭✭

    @EasyGoingPat

    Thank you for the quick response! I have not been able to get the ResourceDictionary to work, from any XAML pages. If I add the color elements to the App.xaml Resources, I don't get any build errors. I would really like to use the merged dictionary functionality, so that we can keep the styles in separate files (for organization sake).

    To give some background, I am working on a cross-platform app that handles all the UI stuff programatically, and we're starting to move the UI layer to XAML. I have never seen this problem, but I have never done this stuff from scratch before. Our NuGet Packages show we're using Xamarin.Forms v3.2.0.839982 (latest), which should allow to use the shorthand merged dictionaries, correct?

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @tsgriggs2

    The version of Xamarin you are using should allow for Merged Dictionaries, yes.

    Are you still having problems? If you are, I may be able to send you a link to some working code that shows how I have set mine up. It may help you to work out what is wrong with your implementation.

    ~ Patrick

  • NMackayNMackay GBInsider, University mod

    @tsgriggs2 said:
    @EasyGoingPat

    Thank you for the quick response! I have not been able to get the ResourceDictionary to work, from any XAML pages. If I add the color elements to the App.xaml Resources, I don't get any build errors. I would really like to use the merged dictionary functionality, so that we can keep the styles in separate files (for organization sake).

    To give some background, I am working on a cross-platform app that handles all the UI stuff programatically, and we're starting to move the UI layer to XAML. I have never seen this problem, but I have never done this stuff from scratch before. Our NuGet Packages show we're using Xamarin.Forms v3.2.0.839982 (latest), which should allow to use the shorthand merged dictionaries, correct?

    This approach definitely works in 3.2.0, I was doing this last week. Why not create a little repo project and post as an attachment so we can take a look.

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    @NMackay
    @tsgriggs2
    @AbhijitDeshpande

    This is a link to a small demo of how I set up my Xamarin MergedDictionaries. Hope it helps.
    https://1drv.ms/u/s!AjTIcJqQTWAFknJRxN97kpfk3gOR

    • Patrick
  • tsgriggs2tsgriggs2 Member ✭✭
    edited October 2018

    @EasyGoingPat
    @NMackay
    Thanks again! There didn't seem to be any reason that the dictionaries wouldn't work, so I decided that the best approach was for me to start with a new project and migrate the code piece by piece. The dictionaries seem to be working in the new project, so I think I am good. I appreciate the help, and I will post again, if I run into more trouble!

  • Excellent question and answer, @EasyGoingPat. Does anyone know how you might set the source to a path in a different project, in this line:

    <ResourceDictionary Source="Styles/Colours.xaml"/>

    Thanks!

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @CharlieFinlayson.3926

    Mmm... good question. You probably need something like this WPF feature: https://docs.microsoft.com/en-us/dotnet/framework/wpf/app-development/pack-uris-in-wpf

    Not sure if Xamarin supports anything like that.

    ~ Patrick

  • Thanks Patrick. That's a good shout. I'll let you know how I get on.

  • MartinBrekhofMartinBrekhof NLUniversity ✭✭

    @CharlieFinlayson.3926 said:
    Excellent question and answer, @EasyGoingPat. Does anyone know how you might set the source to a path in a different project, in this line:

    <ResourceDictionary Source="Styles/Colours.xaml"/>

    Thanks!

    I got it (finally) compiling and running using the following syntax, note the forward slash :

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @MartinBrekhof said:

    <ResourceDictionary Source="Styles/Colours.xaml"/>

    So that accesses XAML styles in a different project?

  • MartinBrekhofMartinBrekhof NLUniversity ✭✭
    edited November 2018 Accepted Answer

    Can be done:
    1. add the file with styles to your current project as a linked file
    2. make sure it has Build action (properties) defined as EmbeddedResource

    I added it to the root of my project (where app.xaml lives).

    hth
    Martin

Sign In or Register to comment.