using WPFluent.Controls; using WPFluent.Extensions; namespace WPFluent.Appearance; /// /// Allows to manage the application theme by swapping resource dictionaries containing dynamic resources with color /// information. /// /// /// ApplicationThemeManager.Apply( ApplicationTheme.Light ); if /// (ApplicationThemeManager.GetAppTheme() == ApplicationTheme.Dark) { ApplicationThemeManager.Apply( /// ApplicationTheme.Light ); } ApplicationThemeManager.Changed += (theme, accent) => { /// Debug.WriteLine($"Application theme changed to {theme.ToString()}"); }; /// public static class ApplicationThemeManager { internal const string LibraryNamespace = "WPFluent;"; public const string ThemesDictionaryPath = "pack://application:,,,/WPFluent;component/Themes/"; private static ApplicationTheme _cachedApplicationTheme = ApplicationTheme.Unknown; /// /// Event triggered when the application's theme is changed. /// public static event ThemeChangedEvent? Changed; /// /// Tries to guess the currently set application theme. /// private static void FetchApplicationTheme() { ResourceDictionaryManager appDictionaries = new(LibraryNamespace); ResourceDictionary? themeDictionary = appDictionaries.GetDictionary("theme"); if (themeDictionary == null) { return; } string themeUri = themeDictionary.Source.ToString(); if (themeUri.Contains("light", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.Light; } if (themeUri.Contains("dark", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.Dark; } if (themeUri.Contains("highcontrast", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.HighContrast; } } /// /// Applies Resources in the . /// public static void Apply(FrameworkElement frameworkElement) { if (frameworkElement.Resources.MergedDictionaries.Count < UiApplication.Current.Resources.MergedDictionaries.Count) { foreach (var dictionary in UiApplication.Current.Resources.MergedDictionaries) { frameworkElement.Resources.MergedDictionaries.Add(dictionary); } } foreach (System.Collections.DictionaryEntry resource in UiApplication.Current.Resources) { System.Diagnostics.Debug .WriteLine( $"INFO | {typeof(ApplicationThemeManager)} Copy Resource {resource.Key} - {resource.Value}", "WPFluent.Appearance"); frameworkElement.Resources[resource.Key] = resource.Value; } } /// /// Changes the current application theme. /// /// Theme to set. /// Whether the custom background effect should be applied. /// Whether the color accents should be changed. public static void Apply( ApplicationTheme applicationTheme, WindowBackdropType backgroundEffect = WindowBackdropType.Mica, bool updateAccent = true) { if (updateAccent) { ApplicationAccentColorManager.Apply( ApplicationAccentColorManager.GetColorizationColor(), applicationTheme, false); } if (applicationTheme == ApplicationTheme.Unknown) { return; } ResourceDictionaryManager appDictionaries = new(LibraryNamespace); string themeDictionaryName = "Light"; switch (applicationTheme) { case ApplicationTheme.Dark: themeDictionaryName = "Dark"; break; case ApplicationTheme.HighContrast: themeDictionaryName = GetSystemTheme() switch { SystemTheme.HC1 => "HC1", SystemTheme.HC2 => "HC2", SystemTheme.HCBlack => "HCBlack", SystemTheme.HCWhite => "HCWhite", _ => "HCWhite", }; break; } bool isUpdated = appDictionaries.UpdateDictionary( "theme", new Uri($"{ThemesDictionaryPath}{themeDictionaryName}.xaml", UriKind.Absolute)); System.Diagnostics.Debug .WriteLine( $"INFO | {typeof(ApplicationThemeManager)} tries to update theme to {themeDictionaryName} ({applicationTheme}): {isUpdated}", nameof(ApplicationThemeManager)); if (!isUpdated) { return; } SystemThemeManager.UpdateSystemThemeCache(); _cachedApplicationTheme = applicationTheme; Changed?.Invoke(applicationTheme, ApplicationAccentColorManager.SystemAccent); if (UiApplication.Current.MainWindow is Window mainWindow) { WindowBackgroundManager.UpdateBackground(mainWindow, applicationTheme, backgroundEffect); } } public static void ApplySystemTheme() { ApplySystemTheme(true); } public static void ApplySystemTheme(bool updateAccent) { SystemThemeManager.UpdateSystemThemeCache(); SystemTheme systemTheme = GetSystemTheme(); ApplicationTheme themeToSet = ApplicationTheme.Light; if (systemTheme is SystemTheme.Dark or SystemTheme.CapturedMotion or SystemTheme.Glow) { themeToSet = ApplicationTheme.Dark; } else if (systemTheme is SystemTheme.HC1 or SystemTheme.HC2 or SystemTheme.HCBlack or SystemTheme.HCWhite) { themeToSet = ApplicationTheme.HighContrast; } Apply(themeToSet, updateAccent: updateAccent); } /// /// Gets currently set application theme. /// /// if something goes wrong. public static ApplicationTheme GetAppTheme() { if (_cachedApplicationTheme == ApplicationTheme.Unknown) { FetchApplicationTheme(); } return _cachedApplicationTheme; } /// /// Gets currently set system theme. /// /// if something goes wrong. public static SystemTheme GetSystemTheme() { return SystemThemeManager.GetCachedSystemTheme(); } /// /// Gets a value that indicates whether the application is matching the system theme. /// /// if the application has the same theme as the system. public static bool IsAppMatchesSystem() { ApplicationTheme appApplicationTheme = GetAppTheme(); SystemTheme sysTheme = GetSystemTheme(); return appApplicationTheme switch { ApplicationTheme.Dark => sysTheme is SystemTheme.Dark or SystemTheme.CapturedMotion or SystemTheme.Glow, ApplicationTheme.Light => sysTheme is SystemTheme.Light or SystemTheme.Flow or SystemTheme.Sunrise, _ => appApplicationTheme == ApplicationTheme.HighContrast && SystemThemeManager.HighContrast }; } /// /// Gets a value that indicates whether the application is currently using the high contrast theme. /// /// if application uses high contrast theme. public static bool IsHighContrast() => _cachedApplicationTheme == ApplicationTheme.HighContrast; /// /// Checks if the application and the operating system are currently working in a dark theme. /// public static bool IsMatchedDark() { ApplicationTheme appApplicationTheme = GetAppTheme(); SystemTheme sysTheme = GetSystemTheme(); if (appApplicationTheme != ApplicationTheme.Dark) { return false; } return sysTheme is SystemTheme.Dark or SystemTheme.CapturedMotion or SystemTheme.Glow; } /// /// Checks if the application and the operating system are currently working in a light theme. /// public static bool IsMatchedLight() { ApplicationTheme appApplicationTheme = GetAppTheme(); SystemTheme sysTheme = GetSystemTheme(); if (appApplicationTheme != ApplicationTheme.Light) { return false; } return sysTheme is SystemTheme.Light or SystemTheme.Flow or SystemTheme.Sunrise; } /// /// Gets a value that indicates whether the Windows is currently using the high contrast theme. /// /// if system uses high contrast theme. public static bool IsSystemHighContrast() => SystemThemeManager.HighContrast; }