Skip to main content

Overview

Flowery.Uno provides comprehensive theme switching capabilities through DaisyThemeManager and specialized controls. This guide covers advanced patterns for theme persistence, programmatic management, and custom workflows.
For basic theme switching, see the Theming Guide. This guide focuses on advanced patterns and edge cases.

DaisyThemeController Modes

DaisyThemeController is a flexible toggle control that supports multiple presentation modes for theme switching.

Mode: Toggle

A simple toggle switch between two themes.
<daisy:DaisyThemeController
    Mode="Toggle"
    UncheckedTheme="Light"
    CheckedTheme="Dark" />

Mode: Checkbox

Checkbox-style presentation.
<daisy:DaisyThemeController
    Mode="Checkbox"
    UncheckedTheme="Corporate"
    CheckedTheme="Synthwave" />

Mode: Swap

Animated sun/moon swap indicator.
<daisy:DaisyThemeController
    Mode="Swap"
    UncheckedTheme="Light"
    CheckedTheme="Dark" />
The Swap mode provides a delightful animated transition between light (sun) and dark (moon) themes.

Mode: ToggleWithText

Toggle with custom text labels.
<daisy:DaisyThemeController
    Mode="ToggleWithText"
    UncheckedTheme="Light"
    CheckedTheme="Synthwave"
    UncheckedLabel="Light"
    CheckedLabel="Synthwave" />

Mode: ToggleWithIcons

Toggle with sun/moon icons.
<daisy:DaisyThemeController
    Mode="ToggleWithIcons"
    UncheckedTheme="Light"
    CheckedTheme="Dark" />

Theme Persistence

Persisting user theme preferences requires applying the saved theme before UI construction.

Application Startup Pattern

1

Load saved theme

Retrieve the theme preference from settings/storage.
2

Apply theme first

Call DaisyThemeManager.ApplyTheme() before creating the main window.
3

Create UI

Instantiate and activate the main window. Controls will sync to the current theme.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    // 1. Load saved theme preference
    var savedTheme = LoadThemeFromSettings() ?? "Dark";
    
    // 2. Apply theme BEFORE creating UI
    DaisyThemeManager.ApplyTheme(savedTheme);
    
    // 3. Now create the main window
    MainWindow = new MainWindow();
    MainWindow.Activate();
}

private string? LoadThemeFromSettings()
{
    try
    {
        var settings = ApplicationData.Current.LocalSettings;
        return settings.Values["AppTheme"] as string;
    }
    catch
    {
        return null;
    }
}

Saving Theme Changes

Subscribe to ThemeChanged to persist user selections:
public MainWindow()
{
    InitializeComponent();
    
    DaisyThemeManager.ThemeChanged += OnThemeChanged;
}

private void OnThemeChanged(object? sender, string themeName)
{
    SaveThemeToSettings(themeName);
}

private void SaveThemeToSettings(string themeName)
{
    try
    {
        var settings = ApplicationData.Current.LocalSettings;
        settings.Values["AppTheme"] = themeName;
    }
    catch (Exception ex)
    {
        // Log error
    }
}

Using StateStorageProvider

For consistency with Flowery.Uno’s persistence layer:
using Flowery.Services;

private const string ThemeKey = "app.theme";

private string? LoadThemeFromSettings()
{
    return StateStorageProvider.Read<string>(ThemeKey);
}

private void SaveThemeToSettings(string themeName)
{
    StateStorageProvider.Write(ThemeKey, themeName);
}

Programmatic Theme Management

Apply Theme

DaisyThemeManager.ApplyTheme("Synthwave");

Get Current Theme

var currentTheme = DaisyThemeManager.CurrentThemeName;
Console.WriteLine($"Current theme: {currentTheme}");

Check if Theme is Dark

if (DaisyThemeManager.IsDarkTheme("Dracula"))
{
    // Adjust UI for dark theme
}

// Check current theme
if (DaisyThemeManager.IsDarkTheme(DaisyThemeManager.CurrentThemeName))
{
    StatusBar.Foreground = Brushes.White;
}

List Available Themes

foreach (var theme in DaisyThemeManager.AvailableThemes)
{
    Console.WriteLine($"{theme.Name} (Dark: {theme.IsDark})");
}

ThemeChanged Event

DaisyThemeManager.ThemeChanged += (sender, themeName) =>
{
    Console.WriteLine($"Theme changed to: {themeName}");
    UpdateCustomUI();
};

Custom Theme Workflows

Theme Picker with Preview

Show all themes in a grid with live preview:
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    
    <!-- Preview Area -->
    <Border Grid.Row="0"
            Background="{ThemeResource DaisyBase100Brush}"
            Padding="24">
        <StackPanel Spacing="12">
            <TextBlock Text="Theme Preview"
                       Foreground="{ThemeResource DaisyBaseContentBrush}"
                       Style="{StaticResource TitleTextBlockStyle}" />
            <daisy:DaisyButton Content="Primary Button" Variant="Primary" />
            <daisy:DaisyButton Content="Secondary Button" Variant="Secondary" />
            <daisy:DaisyCard Title="Sample Card">
                <TextBlock Text="Card content with current theme." />
            </daisy:DaisyCard>
        </StackPanel>
    </Border>
    
    <!-- Theme Selector -->
    <daisy:DaisyThemeDropdown
        Grid.Row="1"
        MinWidth="220"
        Margin="12" />
</Grid>

Conditional Theme Logic

public void ApplyAppropriateTheme()
{
    var hour = DateTime.Now.Hour;
    
    // Auto dark mode at night
    if (hour >= 20 || hour < 6)
    {
        DaisyThemeManager.ApplyTheme("Dark");
    }
    else
    {
        DaisyThemeManager.ApplyTheme("Light");
    }
}

Theme Rotation

public void CycleTheme()
{
    var themes = DaisyThemeManager.AvailableThemes.ToList();
    var current = DaisyThemeManager.CurrentThemeName;
    var currentIndex = themes.FindIndex(t => t.Name == current);
    
    var nextIndex = (currentIndex + 1) % themes.Count;
    DaisyThemeManager.ApplyTheme(themes[nextIndex].Name);
}

Random Theme

public void ApplyRandomTheme()
{
    var themes = DaisyThemeManager.AvailableThemes.ToList();
    var random = new Random();
    var theme = themes[random.Next(themes.Count)];
    
    DaisyThemeManager.ApplyTheme(theme.Name);
}

Advanced Patterns

Per-Window Theme Override

Apply different themes to different windows:
public class ThemedWindow : Window
{
    public string WindowTheme { get; set; } = "Light";
    
    public ThemedWindow()
    {
        InitializeComponent();
        Activated += OnActivated;
        DaisyThemeManager.ThemeChanged += OnGlobalThemeChanged;
    }
    
    private void OnActivated(object sender, WindowActivatedEventArgs args)
    {
        if (args.WindowActivationState != WindowActivationState.Deactivated)
        {
            DaisyThemeManager.ApplyTheme(WindowTheme);
        }
    }
    
    private void OnGlobalThemeChanged(object? sender, string themeName)
    {
        // Restore window theme if different
        if (themeName != WindowTheme && IsActive)
        {
            DaisyThemeManager.ApplyTheme(WindowTheme);
        }
    }
}
Per-window theming is complex and can lead to visual inconsistencies. Use sparingly.

Theme Transition Animation

Animate theme changes with opacity transitions:
private async Task ApplyThemeWithTransition(string themeName)
{
    // Fade out
    var fadeOut = new DoubleAnimation
    {
        From = 1.0,
        To = 0.0,
        Duration = TimeSpan.FromMilliseconds(150)
    };
    
    Storyboard.SetTarget(fadeOut, RootGrid);
    Storyboard.SetTargetProperty(fadeOut, "Opacity");
    
    var storyboard = new Storyboard();
    storyboard.Children.Add(fadeOut);
    storyboard.Begin();
    
    await Task.Delay(150);
    
    // Apply theme
    DaisyThemeManager.ApplyTheme(themeName);
    
    // Fade in
    var fadeIn = new DoubleAnimation
    {
        From = 0.0,
        To = 1.0,
        Duration = TimeSpan.FromMilliseconds(150)
    };
    
    Storyboard.SetTarget(fadeIn, RootGrid);
    Storyboard.SetTargetProperty(fadeIn, "Opacity");
    
    var fadeInStoryboard = new Storyboard();
    fadeInStoryboard.Children.Add(fadeIn);
    fadeInStoryboard.Begin();
}

Theme Analytics

Track theme usage:
public class ThemeAnalytics
{
    private readonly Dictionary<string, int> _themeUsage = new();
    
    public ThemeAnalytics()
    {
        DaisyThemeManager.ThemeChanged += OnThemeChanged;
    }
    
    private void OnThemeChanged(object? sender, string themeName)
    {
        if (!_themeUsage.ContainsKey(themeName))
            _themeUsage[themeName] = 0;
        
        _themeUsage[themeName]++;
        
        SaveAnalytics();
    }
    
    public string GetMostUsedTheme()
    {
        return _themeUsage.OrderByDescending(kvp => kvp.Value)
                         .FirstOrDefault().Key ?? "Dark";
    }
    
    private void SaveAnalytics()
    {
        StateStorageProvider.Write("theme.analytics", _themeUsage);
    }
}

Troubleshooting

Theme Doesn’t Update

Ensure you’re using {ThemeResource} instead of {StaticResource} for palette brushes:
<!-- ✅ DO -->
<Border Background="{ThemeResource DaisyBase100Brush}" />

<!-- ❌ DON'T -->
<Border Background="{StaticResource DaisyBase100Brush}" />
Controls created in code-behind need manual updates:
private void OnLoaded(object sender, RoutedEventArgs e)
{
    DaisyThemeManager.ThemeChanged += OnThemeChanged;
    ApplyTheme();
}

private void OnUnloaded(object sender, RoutedEventArgs e)
{
    DaisyThemeManager.ThemeChanged -= OnThemeChanged;
}

private void OnThemeChanged(object? sender, string themeName)
{
    ApplyTheme();
}

private void ApplyTheme()
{
    MyBorder.Background = DaisyResourceLookup.GetBrush("DaisyBase200Brush");
}
Add a handler to confirm the event is firing:
DaisyThemeManager.ThemeChanged += (s, theme) =>
{
    Debug.WriteLine($"Theme changed to: {theme}");
};

Controls Don’t Sync to Theme

Theme must be applied before controls are instantiated. See Theme Persistence.
Ensure controls subscribe to ThemeChanged in Loaded and unsubscribe in Unloaded.

Theme Persistence Issues

Don’t save only on app shutdown - save immediately when theme changes:
DaisyThemeManager.ThemeChanged += (s, theme) =>
{
    SaveThemeToSettings(theme);
};
Load theme before new MainWindow() in OnLaunched.

Best Practices

Use {ThemeResource} for all palette brushes to ensure runtime updates.
Always unsubscribe from ThemeChanged in Unloaded to prevent memory leaks.
Save theme preference immediately when changed, not on app shutdown.
Apply saved theme in OnLaunched before creating any UI.
Use controls like DaisyThemeController with Mode="Swap" for delightful feedback.
Always test your app in both light and dark themes to ensure contrast and readability.

Build docs developers (and LLMs) love