dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.89k stars 1.69k forks source link

OnPlatform in ResourceDictionary Source causes compile error #19573

Open ppereira-serviceonsites opened 7 months ago

ppereira-serviceonsites commented 7 months ago

Description

The following code in App.xaml:

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="{OnPlatform 'Resources/Styles/Colors.xaml',
                    iOS='Resources/Styles/Colors.ios.xaml', 
                    Android='Resources/Styles/Colors.android.xaml'}"/>
                <ResourceDictionary Source="{OnPlatform 'Resources/Styles/Styles.xaml',
                    iOS='Resources/Styles/Styles.ios.xaml', 
                    Android='Resources/Styles/Styles.android.xaml'}"/>
            </ResourceDictionary.MergedDictionaries>

Produces the following compile time error: App.xaml : XamlC error : The given key was not present in the dictionary.

Steps to Reproduce

  1. Create platform specific color and style files
  2. Add code to merge dictionaries based OnPlatform as shown in the App.xaml
  3. Compile

Link to public reproduction project repository

No response

Version with bug

8.0.3

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

I was not able test on other platforms

Affected platform versions

No response

Did you find any workaround?

I've tried conditional compile which actually is preferable in code behind like this:

        var colors = new ResourceDictionary();
        var styles = new ResourceDictionary();
#if IOS
        colors.Source = new Uri("Resources/Styles/Colors.ios.xaml", UriKind.Relative);
        styles.Source = new Uri("Resources/Styles/Styles.ios.xaml", UriKind.Relative);
#elif ANDROID
        colors.Source = new Uri("Resources/Styles/Colors.android.xaml", UriKind.Relative);
        styles.Source = new Uri("Resources/Styles/Styles.android.xaml", UriKind.Relative);
#else
        colors.Source = new Uri("Resources/Styles/Colors.xaml", UriKind.Relative);
        styles.Source = new Uri("Resources/Styles/Styles.xaml", UriKind.Relative);
#endif
        Current.Resources.MergedDictionaries.Add(colors);
        Current.Resources.MergedDictionaries.Add(styles);

which gives me errors at runtime stating that Source must be added in XAML.

I've also tried various other methods including examples that call for providing class names in the resource files and referencing the names... as outlined here: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/theming?view=net-maui-7.0#load-a-theme-at-runtime there is an outstanding issue which is now in backlog that prevents this: https://github.com/dotnet/maui/issues/12390

There seems to be no way to have separate style files per platform. This is a pretty basic need as we all know platforms vary and require tweaks. The alternative would be to go into every style and OnPlatform every setter you need to tweak which becomes unmanageable

Relevant log output

No response

beeradmoore commented 6 months ago

I was able to get this to work in a similar method to your workaround. When I created a new style it created a class with it as well.

MacCatalystStyles.xaml.cs

namespace TestApp.Resources.Styles;

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

MacCatalystStyles.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestApp.Resources.Styles.MacCatalystStyles">
    <Style TargetType="Button">
        <Setter Property="TextColor" Value="Red" />
    </Style>
</ResourceDictionary>

And then loading it in my App.xaml.cs works if I do it like so,

    public App()
    {
        InitializeComponent();

        this.Resources.MergedDictionaries.Add(new MacCatalystStyles());

And then my buttons have red text. Downside is hotreload no longer works. So I need to build my styles in one file and then copy them over when I am done.

RoiChen001 commented 3 months ago

Can repro this issue at Windows/Android/iOS platform on the latest 17.10.0 preview 3(8.0.7&8.0.20).