Table of Contents

SystemThemeWatcher

SystemThemeWatcher automatically synchronizes the application's theme, accent color, and window backdrop with the current Windows theme settings. It listens for system-level changes and applies them to your application in real-time.

Tip

The simplest way to enable system theme tracking is to call SystemThemeWatcher.Watch(this); in your main window's constructor.

How It Works

SystemThemeWatcher attaches a hook to a window's message procedure (WndProc) and listens for the WM_WININICHANGE system message. When Windows broadcasts this message (e.g., when the user changes from light to dark mode), the watcher automatically calls ApplicationThemeManager.ApplySystemTheme() to update your application's appearance.

Basic Usage

Enable theme watching in your window's constructor. This will use the default Mica backdrop and update accent colors.

using Wpf.Ui.Appearance;

public partial class MainWindow : System.Windows.Window
{
    public MainWindow()
    {
        // This will apply the system theme, accent, and default backdrop.
        SystemThemeWatcher.Watch(this);

        InitializeComponent();
    }
}

Customization

You can customize the backdrop effect and control whether the accent color is updated.

Window Backdrop

Specify the WindowBackdropType to apply when the theme changes.

SystemThemeWatcher.Watch(
    this,
    WindowBackdropType.Acrylic // Use Acrylic backdrop
);

Available backdrop types:

  • None: No backdrop effect.
  • Auto: Automatically selects the appropriate backdrop.
  • Mica: The default Windows 11 Mica effect.
  • Acrylic: The semi-transparent Acrylic effect.
  • Tabbed: A blurred wallpaper effect available in recent Windows 11 versions.

Accent Color Updates

You can prevent the watcher from changing the application's accent color.

SystemThemeWatcher.Watch(
    this,
    updateAccents: false // Theme will change, but accent color will not
);

Stop Watching

To stop a window from responding to system theme changes, use the UnWatch method.

SystemThemeWatcher.UnWatch(this);
Important

Do not call UnWatch on a window that has not been loaded, as it will throw an InvalidOperationException. It is safe to call Watch on a window that is not yet loaded.

Dependency Injection Usage

If you are resolving your main window from a dependency injection container, you can start the watcher after the host is built.

var host = Host.CreateDefaultBuilder()
    .ConfigureServices(services =>
    {
        services.AddHostedService<ApplicationHostService>();
        services.AddSingleton<MainWindow>();
        // ... other services
    }).Build();

await host.StartAsync();

var mainWindow = host.Services.GetRequiredService<MainWindow>();

// Watch the window after it's been created
SystemThemeWatcher.Watch(mainWindow);
Note

SystemThemeWatcher works on a static, global basis. While you can Watch multiple windows, the theme and accent settings applied will be the same for all of them based on the parameters of the last Watch call that triggered an update.