Getting Started
What is PresentationTheme Aero?
PresentationTheme Aero is a highly polished Windows Aero theme for WPF. It provides faithful pixel-perfect recreation of the native Aero themes including proper animations depending on system settings, popup drop-shadows, Explorer-styles. Also includes AeroLite and High Contrast themes.
PresentationTheme Aero is open-source software, licensed under the MIT license. The source code is available on its project page on GitHub.
Installation
Install the NuGet package
PresentationTheme.Aero
. The package contains the following assemblies:
Assembly | Description |
---|---|
PresentationTheme.Aero.dll | Shared assembly with utilities |
PresentationTheme.Aero.Win10.dll | Windows 10 Aero theme |
PresentationTheme.AeroLite.Win10.dll | Windows 10 AeroLite theme |
PresentationTheme.HighContrast.Win10.dll | Windows 10 High Contrast theme |
PresentationTheme.Aero.Win8.dll | Windows 8/8.1 Aero theme |
PresentationTheme.AeroLite.Win8.dll | Windows 8/8.1 AeroLite theme |
PresentationTheme.HighContrast.Win8.dll | Windows 8/8.1 High Contrast theme |
Only the first assembly should be referenced. The other theme assemblies are loaded when necessary.
Important
Because the theme assemblies are not (and usually should not) be referenced by projects using PresentationTheme.Aero.dll, they have to be included manually in any packaging or setup.
How do I use the theme?
There are three different ways to use the theme. The differences are summarized in the following table:
Feature | Theme ResourceUri | Theme Policy | Theme Policy with custom resource loader |
---|---|---|---|
Dynamic Theme Changes | Manually | Yes | Yes |
Implicit Theme Styles | No | Yes | Yes |
On-demand Loading | No | No | Yes |
1. Using Theme ResourceUri
The simplest but also most limited way to use the theme is to include the theme resources directly. AeroTheme.ResourceUri returns the Pack URI for the theme resources matching the current system theme. To handle system theme changes subscribe to AeroTheme.ResourceUriChanged and reload the resources.
using PresentationTheme.Aero;
public partial class App
{
public App()
{
// Add theme resources to the application
Resources.MergedDictionaries.Add(new ResourceDictionary {
Source = AeroTheme.ResourceUri
});
// Optional: Handle theme changes.
AeroTheme.ResourceUriChanged += OnAeroThemeChanged;
}
private void OnAeroThemeChanged(object sender, EventArgs args)
{
// Reload theme resources
Resources.MergedDictionaries[0].Source = AeroTheme.ResourceUri;
}
}
The downside to this approach is that the resources are not treated as theme resources by WPF and will not be used as implicit theme styles. That means:
Whenever you define custom styles for standard controls you have to explicitly add a
BasedOn
attribute and reference the previous style:<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}"> </Style>
Even without a custom style, certain controls require an explicit style attribute. For example, a ListView without GridView normally inherits the ListBox style automatically but now requires an explicit style attribute.
<ListView Style="{StaticResource {x:Type ListBox}}"/>
Some elements like the context menu of a TextBox use the default theme style.
2. Using a Theme Policy
The ThemeManager allows setting system theme resources on a per-assembly basis. Doing so uses reflection to set the internal resource dictionary before WPF gets a chance to load the default one.
Replacing the system theme resources solves the downsides of the previous approach and the theme can be used as a drop-in replacement.
using PresentationTheme.Aero;
public partial class App
{
public App()
{
// Set theme resources
AeroTheme.SetAsCurrentTheme();
// Shortcut for:
// ThemeManager.SetPresentationFrameworkTheme(new AeroThemePolicy());
}
}
These calls eventuelly invoke SetTheme
to set the system theme resources. This must be done before WPF attempts to load
the default resources. Otherwise you have to fake a WM_THEMECHANGED
message to
get WPF to reapply all system styles.
Theme policies are automatically reapplied whenever the system theme changes. Using the provided AeroThemePolicy takes care of choosing the appropriate theme resources matching the system theme. It chooses the following theme resource assemblies:
System Theme | Theme Resource Assembly |
---|---|
Windows 10 with Aero theme | PresentationTheme.Aero.Win10.dll |
Windows 10 with Aero Lite theme | PresentationTheme.AeroLite.Win10.dll |
Windows 10 in high contrast mode | PresentationTheme.HighContrast.Win10.dll |
Windows 8/8.1 with Aero theme | PresentationTheme.Aero.Win8.dll |
Windows 8/8.1 with Aero Lite theme | PresentationTheme.AeroLite.Win8.dll |
Windows 8/8.1 in high contrast mode | PresentationTheme.HighContrast.Win8.dll |
Warning
It might be tempting to use a policy that always returns for example Aero regardless of system theme to avoid styling and testing all themes. This will not work reliably since all themes use system colors, mostly for text, and an inverted system theme like high contrast mode can still lead to unreadable text.
3. Using a Theme Policy with custom resource loader
The third and most invasive approach replaces the internal system resource loading mechanism via splicing (i.e., patching code at runtime). The custom resource loader enables on-demand usage of theme policies and allows control libraries to provide styles for specific Windows versions. To enable the resource loader call ThemeManager.Install.
using PresentationTheme.Aero;
public partial class App
{
public App()
{
if (ThemeManager.IsOperational)
ThemeManager.Install();
AeroTheme.SetAsCurrentTheme();
}
}
What about external resource assemblies or third-party libraries?
With the custom resource loader, theme resources for an assembly are resolved as follows:
- If a theme policy is registered for the assembly, use the resource dictionary located using the pack URI returned by IThemePolicy.GetCurrentThemeUri.
- If theme resources are internal, i.e. ThemeDictionaryLocation
is SourceAssembly,
use the resource dictionary in the same assembly located at
pack://application:,,,/{AssemblyName};v{Version};component/themes/{ThemeName}.{ThemeColor}.xaml
. - Use the external resource assembly at
pack://application:,,,/{AssemblyName}.{ThemeName};v{Version};component/themes/{ThemeName}.{ThemeColor}.xaml
. - Fall back to the default theme name and use
pack://application:,,,/{AssemblyName};v{Version};component/themes/{FallbackThemeName}.{ThemeColor}.xaml
(if resources are internal) - Use the external resource assembly at
pack://application:,,,/{AssemblyName}.{FallbackThemeName};v{Version};component/themes/{FallbackThemeName}.{ThemeColor}.xaml
with the following meaning for the placeholders:
{AssemblyName}
: Assembly name (AcmeLibrary
){Version}
: Assembly version (1.0.0.0
){ThemeName}
: Basename of the theme file path returned by GetCurrentThemeName with a Windows version suffix (Win10
,Win8
,Win7
). For the Windows 8 and 10 high contrast theme,HighContrast
is used even though the theme is based on Aero Lite. (Aero.Win10
,AeroLite.Win8
,HighContrast.Win10
){FallbackThemeName}
: Basename of the theme file path.Aero
is replaced byAero2
if Windows 8 or later.{ThemeColor}
: Theme color name returned by GetCurrentThemeName (NormalColor
)
Steps 4 and 5 are equivalent to the default WPF behavior.
For example, for an assembly AcmeLibrary.dll
with version 1.0.0.0
, the
following locations are used in order:
On Windows 10 with the Aero theme:
pack://application:,,,/AcmeLibrary;v1.0.0.0;component/themes/Aero.Win10.NormalColor.xaml
(if the resources are internal)pack://application:,,,/AcmeLibrary.Aero.Win10;v1.0.0.0;component/themes/Aero.Win10.NormalColor.xaml
pack://application:,,,/AcmeLibrary;v1.0.0.0;component/themes/Aero2.NormalColor.xaml
(if the resources are internal)pack://application:,,,/AcmeLibrary.Aero2;v1.0.0.0;component/themes/Aero2.NormalColor.xaml
On Windows 8 with the Aero Lite theme:
pack://application:,,,/AcmeLibrary;v1.0.0.0;component/themes/AeroLite.Win8.NormalColor.xaml
(if theme resources are internal)pack://application:,,,/AcmeLibrary.AeroLite.Win8;v1.0.0.0;component/themes/AeroLite.Win8.NormalColor.xaml
pack://application:,,,/AcmeLibrary;v1.0.0.0;component/themes/AeroLite.NormalColor.xaml
(if theme resources are internal)pack://application:,,,/AcmeLibrary.AeroLite;v1.0.0.0;component/themes/AeroLite.NormalColor.xaml