What's new in WPF for .NET 9

This article describes what's new in Windows Presentation Foundation (WPF) for .NET 9. The main area of focus for WPF this year was improving the visual capabilities of WPF and providing a new theme based on the Fluent design principles for Windows 11.

You can preview the new theme by downloading the WPF Gallery app from the Microsoft Store.

Fluent theme

A new theme is included with WPF that delivers a fresh, modern Windows 11 aesthetic for WPF apps. It includes integrated light and dark modes, and a system accent color support.

  • Fluent theme in light mode:

    A screenshot of the WPF Gallery app, demonstrating the fluent theme in light mode.

  • Fluent theme in dark mode:

    A screenshot of the WPF Gallery app, demonstrating the fluent theme in dark mode

Apply the theme

You can apply the Fluent theme in two ways, setting the ThemeMode property or referencing the Fluent theme resource dictionary. For more information about the theme mode setting, see ThemeMode.

The Fluent theme resource dictionary is available at the following pack URI: /PresentationFramework.Fluent;component/Themes/Fluent.xaml. To apply the resource at the application-level, load the resource into your app's resources:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

The resource dictionary can also be applied to a Window to theme just the window itself.

ThemeMode

A new styling API has been added to WPF, which is exposed through the ThemeMode property. By using this property, you can apply the Fluent style without having to reference a styling resource dictionary directly.

Available values are:

  • Light—Applies the light Fluent theme.
  • Dark—Applies the dark Fluent theme.
  • System—Applies either the light or dark Fluent theme, based on the user's current Windows setting.
  • None—(default) Uses the Aero2 theme.

To apply a theme mode for the whole application, set the ThemeMode property on the Application type. To apply it to a single window, set ThemeMode on the Window type.

For example, style the entire application based on the current light or dark theme set by Windows:

<Application x:Class="MyWpfProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyWpfProject"
             StartupUri="MainWindow.xaml"
             ThemeMode="System">

Here's an example of forcing the light theme, regardless of the theme set by Windows:

<Window x:Class="MyWpfProject.LightWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyWpfProject"
        Title="LightWindow" Height="450" Width="800"
        ThemeMode="Light">

If the ThemeMode is set to any value other than None at the application-level, None can no longer be applied at the window-level.

ThemeMode is designed to respect the settings set by a Fluent Dictionary, allowing you to customize the Fluent theme.

Set in code

Support for changing setting the ThemeMode in code is currently an experimental feature. Accessing the ThemeMode property in code generates error WPF0001, preventing access to the API. Suppress the error to access to the API.

Warning

This API is experimental and subject to change.

First, add the following PropertyGroup element to your project file to suppress the error:

<PropertyGroup>
    <NoWarn>$(NoWarn);WPF0001</NoWarn>
</PropertyGroup>

Tip

You can use the #pragma warning disable WPF0001 directive to suppress the error where it occurs instead of disabling it for the entire project.

Next, set either the ThemeMode property at the application-level or window-level:

// Set light mode at the application-level
Application.Current.ThemeMode = ThemeMode.Light;

// Set dark mode on the current window
this.ThemeMode = ThemeMode.Dark;

Support for Windows accent color

Windows 10 introduced a user-selectable accent color that's used in providing a personal touch or calling out a specific visual element. WPF now supports the user-selected accent color.

The visual color is available as a System.Windows.Media.Color, System.Windows.Media.SolidColorBrush, or System.Windows.ResourceKey. Along with the color itself, light and dark shades of the accent color are available. These are accessed through System.Windows.SystemColors:

Color Color Resource Key Brush Brush Resource Key
Accent AccentColor AccentColorKey AccentColorBrush AccentColorBrushKey
Light 1 AccentColorLight1 AccentColorLight1Key AccentColorLight1Brush AccentColorLight1BrushKey
Light 2 AccentColorLight2 AccentColorLight2Key AccentColorLight2Brush AccentColorLight2BrushKey
Light 3 AccentColorLight3 AccentColorLight3Key AccentColorLight3Brush AccentColorLight3BrushKey
Dark 1 AccentColorDark1 AccentColorDark1Key AccentColorDark1Brush AccentColorDark1BrushKey
Dark 2 AccentColorDark2 AccentColorDark2Key AccentColorDark2Brush AccentColorDark2BrushKey
Dark 3 AccentColorDark3 AccentColorDark3Key AccentColorDark3Brush AccentColorDark3BrushKey

Important

Accent colors are available with or without the Fluent theme.

When creating a UI that uses the accent color, wrap the resource key in a dynamic resource. When a user changes the accent color while the app is opened, the color is updated automatically in the app. For example, here's a TextBlock with the foreground color set to the user's chosen accent color:

<TextBlock Text="First Name:"
           Foreground="{DynamicResource {x:Static SystemColors.AccentColorBrushKey}}" />

Hyphen-based ligature support

WPF has never supported hyphen-based ligatures in UI controls such as the TextBlock. This long-standing community ask was added in .NET 9.

Here's an image of the ligatures not being applied to the glyphs in .NET 8:

A screenshot of a simple WPF app that has a text block showing how glyphs aren't combined into ligatures with .NET 8.

And now, that same text as rendered in .NET 9:

A screenshot of a simple WPF app that has a text block showing how glyphs are combined into ligatures with .NET 9.

BinaryFormatter no longer supported

BinaryFormatter is considered unsafe because it's vulnerable to deserialization attacks, which can lead to denial of service (DoS), information disclosure, or remote code execution. It was implemented before deserialization vulnerabilities were well understood, and its design doesn't follow modern security best practices.

Starting with .NET 9, its implementation has been removed to prevent these security risks. When BinaryFormatter is used, the PlatformNotSupportedException exception is thrown.

WPF used BinaryFormatter in many scenarios, such as when serializing data for clipboard and drag-and-drop operations. Internally, WPF continues to use a safer subset of BinaryFormatter to handle specific use cases with a known set of types.

For more information about BinaryFormatter, see WPF migration guide for BinaryFormatter.