Multi-targeting is a valid approach here, actually. You just need to merge the dictionaries during runtime, just like you would when setting a custom color theme.
In your application's .csproj file, add the following <ItemGroup>
elements (showing Android and Windows only, but the same applies for iOS, etc.):
<!-- Platform specific XAML Android -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.Contains('-android')) == true">
<MauiXaml Update="Resources\Styles\Platform\SpecialStyles.android.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.Contains('-android')) != true">
<MauiXaml Remove="Resources\Styles\Platform\SpecialStyles.android.xaml" />
<None Include="Resources\Styles\Platform\SpecialStyles.android.xaml" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="Resources\Styles\Platform\SpecialStyles.android.xaml.cs" />
<None Include="Resources\Styles\Platform\SpecialStyles.android.xaml.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- Platform specific XAML Windows -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.Contains('-windows')) == true">
<MauiXaml Update="Resources\Styles\Platform\SpecialStyles.windows.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.Contains('-windows')) != true">
<MauiXaml Remove="Resources\Styles\Platform\SpecialStyles.windows.xaml" />
<None Include="Resources\Styles\Platform\SpecialStyles.windows.xaml" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="Resources\Styles\Platform\SpecialStyles.windows.xaml.cs" />
<None Include="Resources\Styles\Platform\SpecialStyles.windows.xaml.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
Then, under the Resources/Styles folder, you could create a new folder called Platform
or similar and add a new Resource XAML file, e.g. SpecialStyles.android.xaml
(and SpecialStyles.android.xaml.cs). Make sure to rename the class and remove the "android" from the name and add some special style you want to apply only on Android, e.g. red background for a Button:
<?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="MauiSamples.Resources.Styles.SpecialStyles">
<Style ApplyToDerivedTypes="True" TargetType="Button">
<Setter Property="BackgroundColor" Value="Red" />
</Style>
</ResourceDictionary>
Also rename the class in the code-behind:
namespace MauiSamples.Resources.Styles;
public partial class SpecialStyles : ResourceDictionary
{
public SpecialStyles()
{
InitializeComponent();
}
}
Do the same for Windows but make the Button green instead:
<?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="MauiSamples.Resources.Styles.SpecialStyles">
<Style ApplyToDerivedTypes="True" TargetType="Button">
<Setter Property="BackgroundColor" Value="Green" />
</Style>
</ResourceDictionary>
Finally, in your App.xaml.cs
, you can merge the resource dictionary with the default resource dictionary as follows:
#if ANDROID || WINDOWS
ICollection<ResourceDictionary> mergedDictionaries = Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(new MauiSamples.Resources.Styles.SpecialStyles());
}
#endif
Attention: Mind the preprocessor directive, this is only necessary, if the SpecialStyles
class only exists for Android or Windows. If you provide a SpecialStyles class for each platform respectively with their own suffix (e.g. SpecialStyles.ios.xaml, etc.), then you wouldn't need the preprocessor directive.
As I was curious about this, I quickly implemented the full sample in my open source MAUI samples GitHub repo: https://github.com/ewerspej/maui-samples
Result on Android:
Result on Windows:
UPDATE
This approach works, I only noticed that the newly created XAML files might disappear from the Solution Explorer, but they still get processed during the build. Apparently, the <MauiXaml>
build action does not get reevaluated in the Solution Explorer according to the selected target framework. I regard this as an inconvenience and I'm happy to update the answer if I find a better solution or if someone has suggestions to improve it.