Skip to content

Commit 6c883e9

Browse files
dipeshmsftHotCakeX
andauthored
Add fluent usage documentation (#10051)
* Added basic Fluent usage documentation * Added more documentation on "Using Fluent theme in WPF in .NET 9" * Addressed review comments * Fixed typo (#10159) * Added a note to Fluent is experimental --------- Co-authored-by: Violet Hansen <[email protected]>
1 parent e145850 commit 6c883e9

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

Documentation/docs/using-fluent.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
2+
# Developer Guide : Using Fluent theme in WPF in .NET 9
3+
4+
> [!NOTE]
5+
> Fluent theme is still in experimental mode and there can be some breaking changes ( like UI behavior, the way in which Fluent is loaded, how the keys are referenced, ThemeMode APIs etc ) in the upcoming .NET releases.
6+
7+
In .NET 9, as part of the ongoing modernization in WPF, we introduced the Fluent ( Windows 11 ) theme. However there are still a lot of gaps that need to be filled. In this document, we describe the behaviors and general ways of using the new Fluent theme. Key-enhancements include :
8+
9+
- Enable Fluent theme at two levels : Application and Window
10+
- Support for Light and Dark themes
11+
- Accent color support
12+
- Default backdrop for windows when using Fluent theme
13+
14+
## Using Fluent theme in your WPF applications
15+
16+
Enabling Fluent theme in WPF application is supported at two levels : **Application** and **Window**.
17+
18+
There are two ways in which you can use \ enable Fluent theme in your WPF Applications - including the Fluent theme resource dictionaries or you can use the experimental **ThemeMode** APIs.
19+
20+
> [!NOTE]
21+
> Both the ways have the same effect i.e. the APIs only includes the ResourceDictionary as convenience.
22+
23+
### Setting Fluent theme by including Fluent theme ResourceDictionary
24+
25+
Fluent theme can be enabled for the whole application by including the Fluent theme ResourceDictionary in App.xaml as follows :
26+
```xml
27+
<Application
28+
x:Class="YourSampleApplication.App"
29+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
30+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
31+
xmlns:local="clr-namespace:YourSampleApplication">
32+
<Application.Resources>
33+
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
34+
</Application.Resources>
35+
</Application>
36+
```
37+
38+
Similary Fluent theme can be enabled for a particular WPF window by including the ResourceDictionary in Window's XAML file as follows:
39+
```xml
40+
<Window
41+
x:Class="YourSampleApplication.MainWindow"
42+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
43+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
45+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
46+
xmlns:local="clr-namespace:YourSampleApplication"
47+
mc:Ignorable="d"
48+
Title="MainWindow" Height="450" Width="800">
49+
<Window.Resources>
50+
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
51+
</Window.Resources>
52+
<Grid>
53+
54+
</Grid>
55+
</Window>
56+
```
57+
58+
By default, when `Fluent.xaml` is included it reacts to the system theme changes. If you want your application to be in Light or Dark mode only include the following dictionaries respectively:
59+
```xml
60+
<!-- For Fluent Light mode -->
61+
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.Light.xaml" />
62+
63+
<!-- For Fluent Dark mode -->
64+
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.Dark.xaml" />
65+
```
66+
67+
### Setting Fluent theme using the experimental ThemeMode APIs
68+
69+
In .NET 9, we also provided ***experimental APIs*** : `Application.ThemeMode` and `Window.ThemeMode` which can be set from XAML or code-behind to enable the Fluent theme in WPF app.
70+
71+
For setting ThemeMode on Application, you can do the following in App.xaml:
72+
```xml
73+
<Application
74+
x:Class="YourSampleApplication.App"
75+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
76+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
77+
xmlns:local="clr-namespace:YourSampleApplication"
78+
ThemeMode="Dark">
79+
<Application.Resources>
80+
81+
</Application.Resources>
82+
</Application>
83+
```
84+
85+
Similary, we can set the ThemeMode on any Window as follows:
86+
```xml
87+
<Window
88+
x:Class="YourSampleApplication.MainWindow"
89+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
90+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
91+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
92+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
93+
xmlns:local="clr-namespace:YourSampleApplication"
94+
mc:Ignorable="d"
95+
Title="MainWindow" Height="450" Width="800" ThemeMode="Dark">
96+
97+
</Window>
98+
```
99+
100+
Since, the API is experimental, for using `ThemeMode` property in code-behind, we need to suppress **WPF0001** warning first. This can be done in the application's project file as follows:
101+
```xml
102+
<PropertyGroup>
103+
<NoWarn>$(NoWarn);WPF0001</NoWarn>
104+
</PropertyGroup>
105+
```
106+
107+
or can be disabled using the `#pragma warning disable WPF0001` directive.
108+
109+
Once, the warning is suppressed, we can use the property from code-behind like this:
110+
111+
```cs
112+
// Sets Fluent theme on Application level
113+
Application.Current.ThemeMode = ThemeMode.Light;
114+
115+
// Sets Fluent theme on one Window
116+
window.ThemeMode = ThemeMode.System;
117+
```
118+
There are 4 static properties defined in ThemeMode struct : `Light`, `Dark`, `System`, `None` and these are the only allowed values for `ThemeMode` right now.
119+
120+
121+
### Expected behavior of the Fluent theme
122+
123+
Irrespective of how you have enabled the Fluent theme, the ThemeMode properties stay in sync with the ResourceDictionary's included in the `Application.Resources` and `Window.Resources`. The points below mention `ThemeMode` but they apply to both the scenarios.
124+
125+
1. When the `ThemeMode` is set to Light or Dark or System, the Fluent Themes are applied to the respective Application or Window.
126+
2. The `ThemeMode` when set to System respects the current operating system's theme settings. This involves detecting whether the user is utilizing a light or dark theme as their App Mode.
127+
3. When the `ThemeMode` is set to None, the Fluent Themes are not applied and the default `Aero2` theme is used.
128+
4. Accent color changes will be adhered to whenever the Fluent Theme is applied irrespective of `ThemeMode`.
129+
5. When the `ThemeMode` is set to a Window, it will take precedence over the Application's `ThemeMode`. In case Window `ThemeMode` is set to None, the window will adhere to Application's `ThemeMode`, even if Application uses Fluent Theme.
130+
6. The default value of `ThemeMode` is None.
131+
7. When **contrast themes** are enabled, HighContrast version of the Fluent theme is applied on the application. In this mode, there is no distinction between light and dark modes and all the window's will appear the same. When we switch back to normal themes, the previously set `ThemeMode` are applied on the windows.
132+
133+
> [!NOTE]
134+
> Even if you include the ResourceDictionary, you will get the same behavior.
135+
136+
> [!NOTE]
137+
> ThemeMode APIs are experimental and subject to change in the later .NET versions.
138+
139+
## Using Accent color brushes in WPF applications
140+
141+
### When using Fluent theme
142+
143+
In Fluent theme color ResourceDictionary's ( Light.xaml, Dark.xaml and HC.xaml ) we have included the following accent color brushes which can be referred using DynamicResource extension and used for writing new styles or customizing existing control styles.
144+
145+
```xml
146+
<!-- Accent Color Brushes defined in Fluent color resource dictionaries -->
147+
<SolidColorBrush x:Key="AccentTextFillColorPrimaryBrush" Color="{StaticResource SystemAccentColorLight3}" />
148+
<SolidColorBrush x:Key="AccentTextFillColorSecondaryBrush" Color="{StaticResource SystemAccentColorLight3}" />
149+
<SolidColorBrush x:Key="AccentTextFillColorTertiaryBrush" Color="{StaticResource SystemAccentColorLight2}" />
150+
<SolidColorBrush x:Key="AccentTextFillColorDisabledBrush" Color="{StaticResource AccentTextFillColorDisabled}" />
151+
152+
<SolidColorBrush x:Key="TextOnAccentFillColorSelectedTextBrush" Color="{StaticResource TextOnAccentFillColorSelectedText}" />
153+
<SolidColorBrush x:Key="TextOnAccentFillColorPrimaryBrush" Color="{StaticResource TextOnAccentFillColorPrimary}" />
154+
<SolidColorBrush x:Key="TextOnAccentFillColorSecondaryBrush" Color="{StaticResource TextOnAccentFillColorSecondary}" />
155+
<SolidColorBrush x:Key="TextOnAccentFillColorDisabledBrush" Color="{StaticResource TextOnAccentFillColorDisabled}" />
156+
157+
<SolidColorBrush x:Key="AccentFillColorSelectedTextBackgroundBrush" Color="{StaticResource SystemAccentColor}" />
158+
<SolidColorBrush x:Key="AccentFillColorDefaultBrush" Color="{StaticResource SystemAccentColorLight2}" />
159+
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush" Opacity="0.9" Color="{StaticResource SystemAccentColorLight2}" />
160+
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush" Opacity="0.8" Color="{StaticResource SystemAccentColorLight2}" />
161+
<SolidColorBrush x:Key="AccentFillColorDisabledBrush" Color="{StaticResource AccentFillColorDisabled}" />
162+
163+
<SolidColorBrush x:Key="SystemFillColorAttentionBrush" Color="{StaticResource SystemAccentColor}" />
164+
165+
```
166+
167+
In High Contrast mode, these brushes are updated to use the system highlight colors.
168+
169+
### Without using Fluent theme
170+
171+
Since, we have introduced AccentColor's similar to how other **SystemColors** were present in WPF, you can use accent colors and accent color brushes by directly referring the resource keys defined in **SystemColors** class like this :
172+
173+
```xml
174+
<StackPanel Orientation="Horizontal" Height="50">
175+
<StackPanel.Resources>
176+
<Style TargetType="Border">
177+
<Setter Property="Height" Value="50" />
178+
<Setter Property="Width" Value="30" />
179+
</Style>
180+
</StackPanel.Resources>
181+
<Border CornerRadius="2 0 0 2" Background="{DynamicResource {x:Static SystemColors.AccentColorDark3BrushKey}}" />
182+
<Border Background="{DynamicResource {x:Static SystemColors.AccentColorDark2BrushKey}}" />
183+
<Border Background="{DynamicResource {x:Static SystemColors.AccentColorDark1BrushKey}}" />
184+
<Border Background="{DynamicResource {x:Static SystemColors.AccentColorBrushKey}}" />
185+
<Border Background="{DynamicResource {x:Static SystemColors.AccentColorLight1BrushKey}}" />
186+
<Border Background="{DynamicResource {x:Static SystemColors.AccentColorLight2BrushKey}}" />
187+
<Border CornerRadius="0 2 2 0" Background="{DynamicResource {x:Static SystemColors.AccentColorLight3BrushKey}}" />
188+
</StackPanel>
189+
```
190+
191+
> [!NOTE]
192+
> When using AccentColor APIs directly, use Light1, Light2 and Light3 variations for Dark mode and Dark1, Dark2 and Dark3 for light mode in your application.
193+
194+
## Backdrop support in WPF
195+
196+
Unlike WinUI, WPF does not have `Acrylic` and `Mica` material, controllers or brushes. For now, to enable backdrop in WPF, we took advantage of the Desktop Window Manager ( DWM ) for specifying the system-drawn backdrop material on a window. We do this by calling the [DwmSetWindowAttribute function](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute) for the window.
197+
198+
We haven't provided any API yet, for switching between the system defined backdrop types ( see [DWM_SYSTEMBACKDROP_TYPE](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) ), as we were not sure of the path we are going to take for this feature.
199+
200+
Rather, when Fluent theme is enabled we set Mica ( DWMSBT_MAINWINDOW ) backdrop on the Window. However, since we need to modify `PresentationSource.CompositionTarget.Background` and call the `DwmExtendFrameIntoClientArea` method, we have provided an app-context switch to disable the applicaiton of backdrop on windows : `Switch.System.Windows.Appearance.DisableFluentThemeWindowBackdrop`.
201+
202+
Developers can disable backdrop in their applications by including the switch as following in their project files :
203+
```xml
204+
<ItemGroup>
205+
<RuntimeHostConfigurationOption Include="Switch.System.Windows.Appearance.DisableFluentThemeWindowBackdrop" Value="True" />
206+
</ItemGroup>
207+
```
208+
209+
or including it in your runtime config file as follows :
210+
211+
```json
212+
{
213+
"runtimeOptions": {
214+
"tfm": "net9.0",
215+
"frameworks": [
216+
// specifications...
217+
],
218+
"configProperties": {
219+
"Switch.System.Windows.Appearance.DisableFluentThemeWindowBackdrop": true,
220+
}
221+
}
222+
}
223+
```
224+
225+
## Going ahead
226+
227+
There are a lot of issues in the styles and the current infrastructure of how Fluent theme is loaded, etc. and we will keep working iteratively to resolve these issues in .NET 10. There are still a lot of features that are still missing that we will work on in the next iteration.
228+
229+
Meanwhile, I would like to ask the community to go ahead and try out the new theme in their applications, and provide us with feedbacks via GitHub issues, discussions, feature suggestions and PRs to make it better.
230+
231+
> [!NOTE]
232+
> While making PRs, make sure to run the `ThemeGenerator.Fluent.ps1` script to auto-generate the combined Fluent theme resource files.

0 commit comments

Comments
 (0)