diff --git a/dotnet-desktop-guide/net/wpf/toc.yml b/dotnet-desktop-guide/net/wpf/toc.yml
index 98f774baa9..a32a4be256 100644
--- a/dotnet-desktop-guide/net/wpf/toc.yml
+++ b/dotnet-desktop-guide/net/wpf/toc.yml
@@ -12,6 +12,8 @@ items:
items:
- name: Overview
href: whats-new/index.md
+ - name: What's new in .NET 9
+ href: whats-new/net90.md
- name: What's new in .NET 8
href: whats-new/net80.md
- name: What's new in .NET 7
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/index.md b/dotnet-desktop-guide/net/wpf/whats-new/index.md
index 35335b7ad8..96fd5b83e6 100644
--- a/dotnet-desktop-guide/net/wpf/whats-new/index.md
+++ b/dotnet-desktop-guide/net/wpf/whats-new/index.md
@@ -1,7 +1,7 @@
---
title: What's new in Windows Presentation Foundation
description: Learn about what's new in Windows Presentation Foundation (WPF). This article covers changes to WPF since .NET 7 was released.
-ms.date: 10/24/2024
+ms.date: 11/07/2024
ms.topic: conceptual
---
@@ -9,11 +9,21 @@ ms.topic: conceptual
Each .NET release introduces a new version of Windows Presentation Foundation (WPF). This article teaches you what's new in each release.
+## .NET 9
+
+More support for building modern apps with WPF with several theming enhancements:
+
+- [Overview of WPF on .NET 9](net90.md)
+- [Fluent theme](net90.md#fluent-theme)
+- [ThemeMode](net90.md#thememode)
+- [Support for Windows accent color](net90.md#support-for-windows-accent-color)
+- [Hyphen-based ligature support](net90.md#hyphen-based-ligature-support)
+
## .NET 8
WPF added hardware acceleration for remote desktop apps, and a new control for browsing and selecting folders in .NET 8.
-- [Overview of WPF on .NET 8](net80.md).
+- [Overview of WPF on .NET 8](net80.md)
- [Hardware acceleration on RDP applications](net80.md#hardware-acceleration)
- [OpenFolderDialog](net80.md#openfolderdialog)
@@ -21,7 +31,7 @@ WPF added hardware acceleration for remote desktop apps, and a new control for b
WPF added some key performance improvements in .NET 7.
-- [Overview of WPF on .NET 7](net70.md).
+- [Overview of WPF on .NET 7](net70.md)
- [Performance improvements](net70.md#performance-improvements)
- [Accessibility improvements and fixes](net70.md#accessibility-improvements-and-fixes)
- [Bug fixes](net70.md#bug-fixes)
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-8.png b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-8.png
new file mode 100644
index 0000000000..f9acaa8cc7
Binary files /dev/null and b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-8.png differ
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-9.png b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-9.png
new file mode 100644
index 0000000000..3f7b73f8eb
Binary files /dev/null and b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/ligature-9.png differ
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-dark.png b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-dark.png
new file mode 100644
index 0000000000..99f0544add
Binary files /dev/null and b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-dark.png differ
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-light.png b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-light.png
new file mode 100644
index 0000000000..11aa7c73a8
Binary files /dev/null and b/dotnet-desktop-guide/net/wpf/whats-new/media/net90/wpf-light.png differ
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/net90.md b/dotnet-desktop-guide/net/wpf/whats-new/net90.md
new file mode 100644
index 0000000000..65919b71a5
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/net90.md
@@ -0,0 +1,123 @@
+---
+title: What's new in WPF for .NET 9
+description: Learn about what's new in Windows Presentation Foundation (WPF) for .NET 9. New versions of WPF are released yearly with .NET.
+ms.topic: whats-new
+ms.date: 11/08/2024
+
+#customer intent: As a developer, I want to know what's changed so that I can remain up-to-date.
+
+---
+
+# 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](https://www.microsoft.com/store/productId/9NDLX60WX4KQ).
+
+## 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:
+
+ :::image type="content" source="./media/net90/wpf-light.png" lightbox="./media/net90/wpf-light.png" alt-text="A screenshot of the WPF Gallery app, demonstrating the fluent theme in light mode.":::
+
+- Fluent theme in dark mode:
+
+ :::image type="content" source="./media/net90/wpf-dark.png" lightbox="./media/net90/wpf-dark.png" alt-text="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](#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:
+
+```xaml
+
+
+
+
+
+
+
+```
+
+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:
+
+:::code language="csharp" source=".\snippets\net90\csharp\App.xaml" range="1-6" highlight="6":::
+
+Here's an example of forcing the light theme, regardless of the theme set by Windows:
+
+:::code language="csharp" source=".\snippets\net90\csharp\LightWindow.xaml" range="1-6" highlight="6":::
+
+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:
+
+:::code language="xml" source=".\snippets\net90\csharp\MyWpfProject.csproj" id="NoWarn":::
+
+> [!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:
+
+:::code language="csharp" source=".\snippets\net90\csharp\MainWindow.xaml.cs" id="ThemeMode":::
+
+## 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:
+
+:::code language="xaml" source=".\snippets\net90\csharp\MainWindow.xaml" id="DynamicAccent":::
+
+## 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:
+
+:::image type="content" source="./media/net90/ligature-8.png" alt-text="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:
+
+:::image type="content" source="./media/net90/ligature-9.png" alt-text="A screenshot of a simple WPF app that has a text block showing how glyphs are combined into ligatures with .NET 9.":::
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml
new file mode 100644
index 0000000000..136c6f3794
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml.cs
new file mode 100644
index 0000000000..18b6b6f085
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/App.xaml.cs
@@ -0,0 +1,13 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace MyWpfProject;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/AssemblyInfo.cs
new file mode 100644
index 0000000000..cc29e7f741
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly:ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml
new file mode 100644
index 0000000000..194250ead6
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml.cs
new file mode 100644
index 0000000000..6f02ea5e20
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/DarkWindow.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace MyWpfProject
+{
+ ///
+ /// Interaction logic for DarkWindow.xaml
+ ///
+ public partial class DarkWindow : Window
+ {
+ public DarkWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml
new file mode 100644
index 0000000000..2f617ea6f2
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml.cs
new file mode 100644
index 0000000000..c4e5ff01ae
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/LightWindow.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace MyWpfProject
+{
+ ///
+ /// Interaction logic for LightWindow.xaml
+ ///
+ public partial class LightWindow : Window
+ {
+ public LightWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml
new file mode 100644
index 0000000000..e863438311
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml.cs
new file mode 100644
index 0000000000..e9b5401bd7
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MainWindow.xaml.cs
@@ -0,0 +1,49 @@
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MyWpfProject;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void ShowDark_Click(object sender, RoutedEventArgs e)
+ {
+ DarkWindow window = new();
+ window.Show();
+ }
+ private void ShowLight_Click(object sender, RoutedEventArgs e)
+ {
+ LightWindow window = new();
+ window.Show();
+ }
+ private void ShowTheme_Click(object sender, RoutedEventArgs e)
+ {
+ ThemeWindow window = new();
+ window.Show();
+ }
+ private void SetLightThemeApp_Click(object sender, RoutedEventArgs e)
+ {
+ //
+ // Set light mode at the application-level
+ Application.Current.ThemeMode = ThemeMode.Light;
+
+ // Set dark mode on the current window
+ this.ThemeMode = ThemeMode.Dark;
+ //
+ }
+}
\ No newline at end of file
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MyWpfProject.csproj b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MyWpfProject.csproj
new file mode 100644
index 0000000000..b3e8de5fb3
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/MyWpfProject.csproj
@@ -0,0 +1,17 @@
+
+
+
+ WinExe
+ net9.0-windows
+ enable
+ enable
+ true
+
+
+
+
+ WPF0001
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml
new file mode 100644
index 0000000000..161dfb5b67
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml.cs
new file mode 100644
index 0000000000..6fee3d594e
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/ThemeWindow.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace MyWpfProject
+{
+ ///
+ /// Interaction logic for ThemeWindow.xaml
+ ///
+ public partial class ThemeWindow : Window
+ {
+ public ThemeWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml
new file mode 100644
index 0000000000..0d80a81b33
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml.cs b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml.cs
new file mode 100644
index 0000000000..4fc374d8fe
--- /dev/null
+++ b/dotnet-desktop-guide/net/wpf/whats-new/snippets/net90/csharp/UserControl1.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MyWpfProject
+{
+ ///
+ /// Interaction logic for UserControl1.xaml
+ ///
+ public partial class UserControl1 : UserControl
+ {
+ public UserControl1()
+ {
+ InitializeComponent();
+ }
+ }
+}