Hello,
I have read the docs regarding SyncFusion theming for .NET MAUI but, for me, it is still unclear how I can change the default colors for the
SyncFusion controls by having light and dark themes.
I have the following code in App.xaml to define my resources:
<?xml version="1.0" encoding="UTF-8" ?>
<Application
x:Class="CoinVibe.App"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:converters="clr-namespace:CoinVibe.Converters"
xmlns:styles="clr-namespace:CoinVibe.Resources.Styles"
xmlns:themes="clr-namespace:Syncfusion.Maui.Themes;assembly=Syncfusion.Maui.Core"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<themes:SyncfusionThemeResourceDictionary />
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
<ResourceDictionary Source="Resources/Styles/RemixIcons.xaml" />
<styles:LightTheme />
</ResourceDictionary.MergedDictionaries>
<converters:ShortDateConverter x:Key="ShortDateConverter" />
<converters:HumanizerDateConverter x:Key="HumanizerDateConverter" />
<converters:CollectionHasItemsConverter x:Key="CollectionHasItemsConverter" />
<converters:StringNotNullOrEmptyConverter x:Key="StringNotNullOrEmptyConverter" />
<converters:StringEndsWithConverter x:Key="StringEndsWithConverter" />
<converters:BoolToStringConverter x:Key="BoolToStringConverter" />
<converters:InverseBoolConverter x:Key="InverseBoolConverter" />
<converters:DateRangeFilterConverter x:Key="DateRangeFilterConverter" />
<converters:BoolToStringOptionsConverter x:Key="BoolToStringOptionsConverter" />
<converters:GuidToStringOptionsConverter x:Key="GuidToStringOptionsConverter" />
<converters:BoolToOpacityConverter x:Key="BoolToOpacityConverter" />
<converters:BoolToNumberConverter x:Key="BoolToNumberConverter" />
<converters:ColorToShadowConverter x:Key="ColorToShadowConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
I have LightTheme.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
x:Class="CoinVibe.Resources.Styles.LightTheme"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<x:String x:Key="SfCardViewTheme">CommonTheme</x:String>
<Color x:Key="SfCardViewBorderColor">#2DD4BF</Color>
<Color x:Key="SfCardViewIndicatorColor">Green</Color>
<Color x:Key="SfCardViewNormalBackround">Green</Color>
</ResourceDictionary>
DarkTheme.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
x:Class="CoinVibe.Resources.Styles.DarkTheme"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<x:String x:Key="SfCardViewTheme">CommonTheme</x:String>
<Color x:Key="SfCardViewBorderColor">White</Color>
<Color x:Key="SfCardViewIndicatorColor">YellowGreen</Color>
<Color x:Key="SfCardViewNormalBackround">YellowGreen</Color>
</ResourceDictionary>
When I change the device light mode, the Syncfusion controls are getting the default colors, ignoring what I have defined in my custom themes.
I am using the following code for listing to theme changes:
public partial class App
{
private readonly ICollection<ResourceDictionary> _mergedDictionaries;
private readonly SyncfusionThemeResourceDictionary? _theme;
private readonly ILogger<App> _logger;
private readonly DarkTheme _darkTheme;
private readonly LightTheme _lightTheme;
public App(AppDbContext appDbContext, ILogger<App> logger, DarkTheme darkTheme, LightTheme lightTheme)
{
_logger = logger;
_darkTheme = darkTheme;
_lightTheme = lightTheme;
try
{
InitializeComponent();
_mergedDictionaries = Resources.MergedDictionaries;
_theme = _mergedDictionaries.OfType<SyncfusionThemeResourceDictionary>().FirstOrDefault();
// Register theme change listener
Current!.RequestedThemeChanged += Current_RequestedThemeChanged;
Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
InitializeDatabase(appDbContext);
LoadThemePreference();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during app initialization");
throw;
}
}
private void InitializeDatabase(AppDbContext appDbContext)
{
try
{
appDbContext.Database.Migrate();
Current!.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>()
.UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
}
catch (SqliteException)
{
_logger.LogWarning("Database corrupted, recreating...");
appDbContext.Database.EnsureDeleted();
appDbContext.Database.Migrate();
}
catch (Exception ex)
{
_logger.LogError(ex, "Database initialization error");
}
}
protected override Window CreateWindow(IActivationState? activationState)
{
var window = new Window(new AppShell());
ApplyStatusBarTheme(window, Current!.RequestedTheme);
return window;
}
private void Current_RequestedThemeChanged(object? sender, AppThemeChangedEventArgs e)
{
ApplyTheme(e.RequestedTheme);
// Update status bar on all windows
foreach (var window in Windows)
{
ApplyStatusBarTheme(window, e.RequestedTheme);
}
}
private void ApplyTheme(AppTheme appTheme)
{
if (_theme is null)
{
return;
}
if (appTheme is AppTheme.Light)
{
_theme.VisualTheme = SfVisuals.MaterialLight;
_mergedDictionaries.Remove(_darkTheme);
_mergedDictionaries.Add(_lightTheme);
}
else
{
_theme.VisualTheme = SfVisuals.MaterialDark;
_mergedDictionaries.Remove(_lightTheme);
_mergedDictionaries.Add(_darkTheme);
}
}
private void LoadThemePreference()
{
var themeSetting = Preferences.Default.Get("theme_preference", "System");
Current!.UserAppTheme = themeSetting switch
{
"Light" => AppTheme.Light,
"Dark" => AppTheme.Dark,
_ => AppTheme.Unspecified
};
ApplyTheme(Current.RequestedTheme);
}
private static void ApplyStatusBarTheme(Window window, AppTheme appTheme)
{
if (Current is null || window.Page is null)
{
return;
}
// Skip status bar theming on Windows platform
#if ANDROID || IOS
var statusBarColorKey = appTheme is AppTheme.Light ? "StatusBarLight" : "StatusBarDark";
var statusBarColor = (Color)Current.Resources[statusBarColorKey];
// Remove any existing StatusBarBehavior to avoid duplicates
var existingBehaviors = window.Page.Behaviors.OfType<StatusBarBehavior>().ToList();
foreach (var behavior in existingBehaviors)
{
window.Page.Behaviors.Remove(behavior);
}
window.Page.Behaviors.Add(new StatusBarBehavior
{
StatusBarColor = statusBarColor
});
#endif
}
private static void Connectivity_ConnectivityChanged(object? sender, ConnectivityChangedEventArgs e)
{
WeakReferenceMessenger.Default.Send(new NetworkAccessChangedEvent(e.NetworkAccess == NetworkAccess.Internet));
}
}
Hi Mihai Alexandru Dumitru,
Greetings from Syncfusion support!
We have created a sample based on your requirements, where the Cards theme keys are customized dynamically based on system theme changes. The sample is attached for your reference. Please review it and try this approach. Let us know if you need any further assistance.
Please refer to the following KB article for more details:
How to Assign Values to Syncfusion Theme Keys for Different Themes in .NET MAUI?
Regards,
Brundha V