WinUI Theming: A Deep Dive into Modern Windows UI Customization

Unlock the potential of your Windows applications with advanced theming techniques.

Published: October 26, 2023 | Author: Microsoft Developer Community | Category: Windows App Development, WinUI

Welcome to an in-depth exploration of WinUI theming. In this post, we'll delve into the powerful capabilities that allow developers to create visually stunning and highly personalized user experiences on Windows. WinUI, the latest native UI platform from Microsoft, offers a robust framework for building modern, beautiful, and performant applications. A key aspect of this is its flexible theming system.

Understanding WinUI's Theming Architecture

WinUI's theming model is built upon a foundation of resource dictionaries and dynamic properties. At its core, it leverages XAML resources to define colors, styles, and templates. These resources can be applied globally to an application or targeted to specific controls, enabling granular customization.

Resource Dictionaries: The Building Blocks

Resource dictionaries are XAML files that contain definitions of various UI elements and properties. In WinUI, these are often used to define:

You can merge multiple resource dictionaries to create complex and layered themes. For example, a base theme might define common elements, while a specific accent theme overrides certain colors.

Theme Resources and Dynamic Properties

WinUI heavily relies on ThemeResources and dynamic properties. When you define a color like this:


<SolidColorBrush x:Key="MyAccentBrush" Color="{ThemeResource AccentColor}" />
            

The application will dynamically pick up the value of AccentColor from the active theme. This allows the entire application's look and feel to change seamlessly just by updating a few key theme resources.

Implementing Custom Themes

Creating your own theme involves defining a set of resources that override or supplement the default WinUI resources.

Step 1: Define Your Color Palette

Create a new XAML file (e.g., MyCustomTheme.xaml) and define your colors:


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Color x:Key="SystemAccentColor">#00A3CF</Color>
    <SolidColorBrush x:Key="SystemAccentBrush" Color="{ThemeResource SystemAccentColor}" />

    <Color x:Key="CustomPrimaryColor">#FF6200EE</Color>
    <SolidColorBrush x:Key="CustomPrimaryBrush" Color="{ThemeResource CustomPrimaryColor}" />

    <Color x:Key="CustomBackgroundColor">#1E1E1E</Color>
    <SolidColorBrush x:Key="CustomBackgroundBrush" Color="{ThemeResource CustomBackgroundColor}" />

    <Color x:Key="CustomTextColor">#F0F0F0</Color>
    <SolidColorBrush x:Key="CustomTextBrush" Color="{ThemeResource CustomTextColor}" />

</ResourceDictionary>
            

Step 2: Merge Your Theme

In your application's main App.xaml (or a similar entry point), merge your custom theme dictionary:


<Application ...>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Themes/MyCustomTheme.xaml" />
                <!-- Other dictionaries like Default.xaml could go here -->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
            

Step 3: Apply Custom Resources

Now, you can use your custom brushes and colors throughout your application:


<Button Content="Click Me" Background="{StaticResource CustomPrimaryBrush}" Foreground="{StaticResource CustomTextBrush}" />
<TextBlock Text="Welcome!" Foreground="{StaticResource CustomTextBrush}" />
<Grid Background="{StaticResource CustomBackgroundBrush}">
    <!-- ... other content -->
</Grid>
            

Dynamic Theme Switching

To enable dynamic theme switching, you need a mechanism to change the active theme resources at runtime. A common approach is to manage a list of merged dictionaries and update the application's resource lookup path.

Example: Switching Between Light and Dark Themes

You can have separate dictionaries for light and dark themes and switch between them by modifying Application.Current.Resources.MergedDictionaries.

DarkTheme.xaml:


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color x:Key="SystemAccentColor">#0078D4</Color>
    <SolidColorBrush x:Key="SystemAccentBrush" Color="{ThemeResource SystemAccentColor}" />
    <Color x:Key="CustomBackgroundColor">#1E1E1E</Color>
    <SolidColorBrush x:Key="CustomBackgroundBrush" Color="{ThemeResource CustomBackgroundColor}" />
    <Color x:Key="CustomTextColor">#F0F0F0</Color>
    <SolidColorBrush x:Key="CustomTextBrush" Color="{ThemeResource CustomTextColor}" />
</ResourceDictionary>
            

LightTheme.xaml:


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color x:Key="SystemAccentColor">#0078D4</Color>
    <SolidColorBrush x:Key="SystemAccentBrush" Color="{ThemeResource SystemAccentColor}" />
    <Color x:Key="CustomBackgroundColor">#FFFFFF</Color>
    <SolidColorBrush x:Key="CustomBackgroundBrush" Color="{ThemeResource CustomBackgroundColor}" />
    <Color x:Key="CustomTextColor">#333333</Color>
    <SolidColorBrush x:Key="CustomTextBrush" Color="{ThemeResource CustomTextColor}" />
</ResourceDictionary>
            

In your C# code-behind:


public void SwitchToDarkTheme()
{
    var appResources = Application.Current.Resources.MergedDictionaries;
    var themeResource = appResources.FirstOrDefault(r => r.Source?.OriginalString.Contains("Theme.xaml") ?? false);

    if (themeResource != null)
    {
        appResources.Remove(themeResource);
    }

    appResources.Add(new ResourceDictionary { Source = new Uri("Themes/DarkTheme.xaml", UriKind.Relative) });
}

public void SwitchToLightTheme()
{
    var appResources = Application.Current.Resources.MergedDictionaries;
    var themeResource = appResources.FirstOrDefault(r => r.Source?.OriginalString.Contains("Theme.xaml") ?? false);

    if (themeResource != null)
    {
        appResources.Remove(themeResource);
    }

    appResources.Add(new ResourceDictionary { Source = new Uri("Themes/LightTheme.xaml", UriKind.Relative) });
}
            

Advanced Theming Techniques

Beyond basic color and style overrides, WinUI allows for:

Conclusion

WinUI's theming system is a powerful tool for creating applications that are not only functional but also aesthetically pleasing and adaptable to user preferences. By mastering resource dictionaries and dynamic properties, you can build truly unique and engaging user experiences for the Windows platform.

Stay tuned for more advanced topics, including animation integration and custom control templating!